CSS3 Text Effects with Webkit Masking
Dead easy but cute little technique this one. I’m working with a design that had an overlay effect over some of the text based headings.
The way I’ve seen it done before (and I have in fact done it myself) is to simply stick a PNG with alpha transparency on top of the text in question. Granted, this technique does work but it felt like a bit of a cludge. It also means you can’t highlight the text underneath it. Annoying and bad for usability.
I then cast my mind back to the stunning Kaleidoscope App website. Using a Webkit browser, look closely at the colour wheel triangle thingy and you’ll notice it’s spinning. Dig deeper in the CSS and you’ll see they’re using a really nice masking technique to achieve that.
Simple enough, but I wanted this effect to appear on all browsers rather than just Webkit.
Detecting Webkit Masking Support
Feature detection is the best way to implement this technique. Rather than just seeing if “browser = Chrome or Webkit”, you can either use the Modernizr library to do this for you, or simply grab the following line of Javascript and insert it above your CSS.
document.documentElement.className = document.documentElement.style.WebkitMask!==undefined?"masking":"nomasking";
That will add a class of ‘masking’ to your HTML tag should the feature be supported. And, by including this pre-CSS, you’ll get no flickering of content. You can then just add the .masking prefix to styles that use it.
Creating the Mask
Basic Photoshop skills should be enough to create pretty much any type of mask. The key point to remember is that they’re unlike Photoshop masks in that they rely on Alpha transparency rather than black or white.
Webkit masks require a PNG with an alpha channel, i.e. a 24 or 32 bit PNG.
Areas of the mask with 0% opacity will hide that section of the element the mask is being applied to. Areas with 100% will render as usual. Then, as you’d expect, you can use anything in-between for partial transparency.
Here’s the mask I’m using. I’ve dropped it in a green container so you can see where the transparency lies.

The CSS
This is the easy bit. For non ‘.masking’ browsers, implement the same ‘overlay’ technique as you’ve no doubt done before.
For browsers that do support Webkit Masking, just override the element (for example, an h1 tag) to set it.
.masking h1 { -webkit-mask-image: url(../img/bg/text-effect-mask.png); }
You can then play with the positioning and things should you need to;
- -webkit-mask-position-y
- -webkit-mask-position-x
- -webkit-mask-repeat
Here’s a screenshot of the output.
A nice, selectable, accessible, progressively enhanced text overlay effect.
Simple right?
This is a rudimentary use of the Webkit mask. As you can see from the Made by Sofa guys (creators of Kaleidoscope App), you can create some amazing effects and choose either to implement a technique for non-supporting browsers, or just degrade gracefully to a static version, as they’ve done.
You can also use them on pretty much any DOM element there is, as the comments on the Surfin’ Safari docs explain.
Tweet Follow @benpbarnettComments are closed.

I was successfully using your excellent jquery.animate-enhanced plugin with jquery-1.4.2. I couldn’t make it without it because my Raphael-generated animated graphs were not working with WebKit browsers in Ctrl++ mode (i.e. when non-default zooming was in place). With your plugin it worked fine – thank you very much!
Now I’m trying to upgrade the app I’m working on to 1.4.3, and I’m back to the same set of animation problems.
My question: what are your plans regarding jQuery 1.4.3?
Please let me know if I could be of any help.
Thanks again for you wonderful job!
-Mike
Very interesting! Thanks Mike I shall be looking into this tomorrow, I haven’t actually used 1.4.3 yet. I’ll compare the versions and see what I can come up with.
When you say the animations aren’t working, do you mean you’re getting errors, or the animation looks awful, or something else?
WIth 1.4.3 the animation behavior is “awful”
It behaves as it used to without your plugin.
I’m animating ‘top’ prop and under zoomed browser (i.e. after applying Ctrl++ or Ctrl+-) it is pretty jerky. It also doesn’t stop in correct place, etc. Again it only happens in WebKit browsers and only if Ctrl+0 is not applied.
Thanks for the quick response. I think I can send you a quick repro if you need it. Just let me know.
Many thanks!
Mike
“Awful” – Excellent, that’s what we’re all aiming for right?!
If you have a demo link somewhere feel free to share it, that may help things. Feel free to email it across if you’d rather not make it public.
Handling zoom in browsers is notoriously tricky to debug as each one seems to handle it differently, even amongst Webkit, but its definitely worth a look.