CSS-Tricks*

A Web Design Community curated by Chris Coyier

Show Image Under Text (with Acceptable Fallback)

By Chris Coyier
On 11/12/2010
With 34 Comments

WebKit supports the cool background-clip CSS3 property, which you can use to do some pretty neat stuff. The first time we touched on it was the iPhone Slide-to-unlock idea where we set a gradient to animate through the background of the text. Then we touched on it again for the transparent borders idea.

Let's take a look at using it to have an image be visibile only through the letters of the text. One more cool thing that we no longer need to drool over print designers ability to do.

View Demo

The Basic Idea

h1 {
   color: white;  /* Fallback: assume this color ON TOP of image */
   background: url(images/fire.jpg) no-repeat;
   -webkit-background-clip: text;
   -webkit-text-fill-color: transparent;
}

That's all there is to it. Set a background image on the element, then clip it out, and set the text fill color to transparent.

The Problem

As I'm sure everyone is painfully aware, this isn't going to work in all browsers. The current support is WebKit only. So what happens for a fallback? As you can see in the code above, you declare a color value as well. This value gets overridden by -webkit-text-fill-color in browsers that support it, so we're clear there. Then in browsers that don't support -webkit-background-clip: text we will see the background image in full, so we will see text on top of that background image. So if you read no further, set a color value that will be nice and visible on that background image.

So we get this going on:

Not the absolute end of the world, at least we prepared the text to be somewhat readable. But this is a long way from what we envision and what WebKit users will experience. Basically: that fallback sucks, let's do better.

A Better Fallback

The ultimate tool for better fallbacks is Modernizr. Simply include the (fairly small) JavaScript file on your page, and it adds classnames to the html tag of your page indicating what the current browser is capable of. It also provides an API for testing features in JavaScript, but we won't need that today.

Unfortunately, Modernizr doesn't have a test for background-clip right out of the box. I asked one of the creators, Paul Irish, who hooked me up with this quick way to add this test. The whole bit:

<script src="modernizr-1.6.min.js"></script>
<script>
	Modernizr.addTest('backgroundclip',function(){

	  var div = document.createElement('div');

	  if ('backgroundClip' in div.style) return true;

	  'Webkit Moz O ms Khtml'.replace(/([A-Za-z]*)/g,function(val){
	    if (val+'BackgroundClip' in div.style) return true;
	  });

	});
</script>

Now we'll know for certain if the current browser supports background-clip, or does not. If it does, the html tag will have a backgroundclip class, if it does not, it will have a no-backgroundclip class.

Now we only apply the background image if we are certain the browser supports background-clip.

.backgroundclip h1 {
	background: url(images/west.jpg) -100px -40px no-repeat;
	-webkit-background-clip: text;
	-webkit-text-fill-color: transparent;
}

h1 {
	color: orangered;
}

Badda bing, now the fallback is a straight up solid color instead of a messy-looking image knockout.

View Demo

Subscribe to The Thread

  1. cooljaz124 says:

    Awesome ! So, Firefox have no luck yet ?

  2. Safari got crashed on my windows ?? Not sure scripts problem or safari in windows ??

    • pceasies says:

      Every time I open a demo on this site it seems Chromium stops responding and the tab crashes. It must be something that’s added on every page, but it’s breaking my browser.

  3. Is FF4 going to support this?

    • John says:

      Currently, the latest FF4 beta (b7) doesn’t support this. Maybe (hopefully) in the future, it will.

  4. That’s really awesome.

    One thing though: won’t that replace method run around 9-10 times, because it will also run for the space between each vendor prefix? Would it be better to use the + instead of the *?

    'Webkit Moz O ms Khtml'.replace(/([A-Za-z]+)/g

    That way, the callback will only run if something was actually captured. As a space is equivalent to false, it will never run in those cases. (But petty, yeah).

    Very cool demo.

  5. Sebastiaan Deckers says:

    I don’t think the second “return true” statement will achieve what is intended, as it is simply returning from within the anonymous function passed to replace(). How about using a returnValue variable and setting it from within the closure, then returning that at the end?

  6. Ralf Hortt says:

    Seems like its broken in FF4 beta7 too. Fallback doesnt work :-/

  7. I just love coming to your site dude, I’m a CSS feather weight, so new stuff like CSS3 blows my mind, sometimes it’s so overwhelming it seems like too much for me to wrap my mind around it. It’s so awesome to find that there are sites like this who helps us through the process. Cheers!

  8. MartinodF says:

    Nice trick.
    Unfortunately, on Android you get the background on the entire div, and no text whatsoever.

  9. Great work Chris! I dig your experiments a ton.

  10. bill says:

    This is one of those effects where my first reaction is why bother? It only works is a couple of browsers and what value does it add? The best solution here would be to create an actual image and not use CSS for this so it can work everywhere.

  11. Paul says:

    Bill,
    Although your point is valid, I would make the argument that Chris is simply presenting a proof of concept. Would you ever need to deploy this to a live site? Maybe so, or maybe not. The more important thing is that Chris is showcasing an experimental CSS3 approach and more importantly showing a graceful fallback.

  12. Excellent work there, Chris. I’m glad you bothered with this:) Baby steps towards a more beautiful web!

  13. Chris says:

    This looks super choppy on Chrome (on XP) when rotated, but fine when horizontal. -webkit-transform issue?

  14. Krystian says:

    This is really cool to see what’s possible with CSS now but I would really use Photoshop to work on this type of effect

  15. Lea Verou says:

    The problem with this test is that it tests for the background-clip property, not for the particular value (text). background-clip is supported by all modern browsers (even IE9), but the “text” value is a non-standard Webkit extension. So, essentially, the “better fallback” would only get applied in old browsers that don’t support background-clip at all, and will fail on modern ones that aren’t Webkit, so they only support the standard values for it.

  16. It is really good. If it works in all browsers, no need to work in Photoshop to create this kind of masking effects.

    -vara

  17. This will be good to use, just wondering about support for other browser than Webkit.

  18. Rogier Borst says:

    This (obviously) also works for gradient backgrounds (like Chris shows in this post.
    However, if you apply text-shadow now, the background won’t show, because apparently the shadow is a solid ‘layer’ underneath the whole text.
    One method to have both gradient text and text shadows is described by Jeffrey Way in this article on nettuts, which involves replicating content in your stylesheet, making that a big no-no for me.
    Webkit should either create a text-shadow-clip property (yeah right) or just allow us to set something like an image or gradient on text color properties instead of just on background properties.

  19. thom says:

    Hahahaha.. it’s amazing. Work in Chrome 7.0 (but ‘the rotated text’ is not, when mouse over, it become straight/ not rotated), not working in FF (just color, no image), and bad in Opera 10 (like div with image background). But nice try :D

  20. Brilliant, really nice use of CSS with text. LT

  21. I was hoping that, when using a moving div (scrolling) and changing the background image to a semi-transparent png this would then allow me to see the image over which the div is being scrolled.

    sadly it does not.

    does anyone know how to ‘punch out’ the text from a div that has a solid colot? Setting the text to transparent doesn’t do the trick.

  22. No Firefox use for these tricks? Works great in Safari, thanks for sharing!

  23. Technokrat says:

    Demo is crashing my Safari every time trying to watch the demo. Maybe this funny looking feature is not perfect

  24. Julian says:

    awesome
    does it work on IE too ?

  25. Mark says:

    Great post! Nice trick! I like it!

  26. JOSE says:

    It crashed the Safari on my W7 as well …

  27. garrett says:

    you could also make a photoshop image if you have i think anything after cs2 and create a clipping mask

It's Your Turn

At this moment, you have an awesome opportunity* to be the person your mother always wanted you to be: kind, helpful, and smart. Do that, and we'll give you a big ol' gold star for the day (literally).

Posting tips:
  • You can use basic HTML
  • When posting code, please turn all
    < characters into &lt;
  • If the code is multi-line, use
    <pre><code></code></pre>
Thank you,
--- The Management ---