Updated April 2014 with more modern information.
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.

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 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.

But… there is no perfect system for this.
There is an issue with Android (up to and including 4.2) where it doesn’t actually support -webkit-background-clip
– even though any test will return that it does. The property, and any value it might have including text
. Even Modernizr’s testAllProps()
can’t catch it. But -webkit-text-fill-color
does work, so essentially you get an image with no text. Pretty bad.
If you absolutely need to use this, you might just need to UA test for Android:
var NastyBrowserSniffing = {
ua: navigator.userAgent.toLowerCase(),
init: function() {
var isAndroid = NastyBrowserSniffing.ua.indexOf("android") > -1;
if (isAndroid) {
$("html").addClass("android");
}
}
};
NastyBrowserSniffing.init();
Then revert the effect if it’s Android:
html.android .gradient-text {
color: white;
background: none;
-webkit-text-fill-color: white;
-webkit-background-clip: border-box;
}
.gradient-text {
background: -webkit-linear-gradient(gray, black);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
Related
Stephen Morley covers how to do it for IE with filters.
Awesome ! So, Firefox have no luck yet ?
Safari got crashed on my windows ?? Not sure scripts problem or safari in windows ??
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.
It’s a pretty neat trick that I tested some time ago: http://valuedstandards.com/static/test/clip.html
However, be advised that WebKit will probably remove support altogether for something else/better like using a value on the
color
property.Is FF4 going to support this?
Currently, the latest FF4 beta (b7) doesn’t support this. Maybe (hopefully) in the future, it will.
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.
Oh I think Sebastiaan is right. Maybe something like this?
Even more succinctly:
'Webkit Moz O ms Khtml'.replace(/\w+/g, ...callback...)
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?
Seems like its broken in FF4 beta7 too. Fallback doesnt work :-/
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!
Nice trick.
Unfortunately, on Android you get the background on the entire div, and no text whatsoever.
Great work Chris! I dig your experiments a ton.
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.
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.
Excellent work there, Chris. I’m glad you bothered with this:) Baby steps towards a more beautiful web!
You quite often leave out -o- prefixes wich with the result that modernizr detects support and doesn’t serve the fallback and instead the rendering is broken like here.
Great tutorial as usual though.
This looks super choppy on Chrome (on XP) when rotated, but fine when horizontal. -webkit-transform issue?
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
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.
You could test for the value “text” only, by trying to apply it to the supported version of the background-clip property and see if the browser accepted it by trying to get it afterwards (in a try…catch construct, since some IEs throw errors for unsupported values). Haven’t tried it, but that usually works for testing CSS values support.
It is really good. If it works in all browsers, no need to work in Photoshop to create this kind of masking effects.
-vara
This will be good to use, just wondering about support for other browser than Webkit.
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.
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
Brilliant, really nice use of CSS with text. LT
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.
No Firefox use for these tricks? Works great in Safari, thanks for sharing!
Demo is crashing my Safari every time trying to watch the demo. Maybe this funny looking feature is not perfect
awesome
does it work on IE too ?
Great post! Nice trick! I like it!
It crashed the Safari on my W7 as well …
you could also make a photoshop image if you have i think anything after cs2 and create a clipping mask
I tried to emulate this property on inline-svg for Mozilla and Opera:
http://www.myadzel.ru/tests/html/text-background/
Sort happened.
Hi, I like the idea of the Modernizr tweak, though it didn’t work for me in FF 27.0.1 as it is showing backgroundclip in that browser.
What about using:
@media(-webkit-min-device-pixel-ratio:0){.textbg{background:url(bg.jpg)}}
.textbg{-webkit-background-clip:text;-webkit-text-fill-color:transparent;-webkit-text-stroke:1px black}
?
You, sir, are FANTASTIC.
What was updated here? For me it applies the backgroundclip-class for all no browsers from Chrome to ie7. Did you test it after the update/with a newer Modernizr?