How To Do Knockout Text

There are a couple of ways to do knockout text (text that appears cut out, such that you can see a background behind it) on the web. There is one fairly new way that has pretty decent browser support that is pretty interesting. But let's cover all the ground.

Just Photoshop It Up

Like anything else, you can just fake it with a flat graphic. Sometimes it's worth covering the obvious. The downsides are it's not dynamic/hard to change. You can't copy-and-paste the text. Images can be large in file size, especially as you fight for higher resolution. Etc etc. But, you can do it and it'll work everywhere:

-webkit-background-clip: text;

This is a non-standardized property, but it was invented to do just this. The beauty is that you can pair it with -webkit-text-fill-color: transparent; so that you're only "hiding" the text in a browser that can do the clipping. Divya Manian documented this a few years back.

.clip-text-maybe {
  
  /* if we can clip, do it */
  -webkit-text-fill-color: transparent;
  -webkit-background-clip: text;

  /* what will show through the text
      ~ or ~
     what will be the background of that element */
  background: whatever;

  /* fallback text color
      ~ or ~
     the actual color of text, so it better work on the background */
  color: red;
 
}

This is real web text, so with that comes all the accessibility and searchability and easy-to-change-ness and all that.

Here's some fun examples of this method at work, by Jintos:

See the Pen -webkit-background-clip:text CSS effect by Jintos (@Jintos) on CodePen.

Like any other background, you can fix its position if that's desireable. Here's a demo of that by Richard Hayes:

See the Pen Webkit Clip with Fixed Background by Richard (@strawstack) on CodePen.

SVG <pattern> fill

SVG can also have real text, through it's <text> element. SVG text can be filled with whatever, including a pattern. And a pattern can use an image. So... knockout text!

An example of that would be like:

<svg>
  <pattern id="pattern" patternUnits="userSpaceOnUse" width="750" height="800">
    <image width="750" height="800" xlink:href="image.jpg"></image>
  </pattern>
  <text x="0" y="80" class="headline" style="fill:url(#pattern);">background-clip: text | Polyfill</text>
</svg>

Which you could use right in HTML anywhere. Here's an example of that by C.Y. Park:

See the Pen SVG Text Clip with Gradient & GIF by C.Y. Park (@cypark) on CodePen.

Lea Verou also documented this technique.

Polyfill the CSS with SVG

Tim Pietrusky created a polyfill for -webkit-background-clip that uses the SVG method as a fallback. The CSS version is certainly easier to write quickly than the SVG version, so it seems like this could be a good way to go while still getting better browser support.

See the Pen -webkit-background-clip: text Polyfill by Tim Pietrusky (@TimPietrusky) on CodePen.

mix-blend-mode: screen;

This is the new one I hadn't seen before! CSS blending is fairly new. It allows you to blend elements on top of other elements like you would layer styles in Photoshop (e.g. "screen", "multiply", "lighten", etc.)

Done just right, you can blend an image right on top of text without affecting the "real" background. I first saw Giana do it on CodePen:

See the Pen CSS Gradient Text in Firefox by Giana (@giana) on CodePen.

It works like this:

  1. Make the text black.
  2. Cover the entire text with the new text background and mix-blend-mode: screen;
  3. Then cover that with a new copy of the same text (in white) and the same background as the page and mix-blend-mode: multiply;

That will leave just the text with the "knockout" background visible. If you use pointer-events, you can leave the text clickable and selectable too, although it's hard to see what you're doing.

The advantage here is that this is a pure-CSS method that works in Firefox as well, not just -webkit- stuff.