Grow your CSS skills. Land your dream job.

Animated Knockout Letters

Published by Chris Coyier

I was watching some commercial the other day and they had these letters fly in over a black screen and reveal an image beneath them. It was a pretty cool looking effect and it reminded me how WebKit has that cool -webkit-background-clip property which allows you to show background through text. So I set off on trying to see if I could do something like that. You can, but there are some interested stumbling points...

This is the final product:

View Demo   Download Files

This will only look right in WebKit browsers (Safari, Mobile Safari, Chrome). The download won't have the fancy font (see below).

Knockout Basics

There isn't much to it:

.display-sweet-image-behind {
   /* fallback color */
   color: white; 

   /* overrides color with nothingness */
   -webkit-text-fill-color: transparent;
   /* remember non WebKit browsers will see all of this EXCEPT the text */
   background: url(images/zombies-making-out.jpg) no-repeat; 

   /* the magic */
   -webkit-background-clip: text;

   font: bold 100px Impact, Sans-Serif;
<div class="display-sweet-image-behind">Nom nom nom</div>

Moving the letters around

Turns out it's totally cool if you wrap the letters in spans, like this:

<div class="display-sweet-image-behind">
nom nom

The letters will still knock out and all is well. It's not just spans, it's that you are wrapping them in an inline level element. If you use inline-block, or block, or anything else, the knockout stops working. =(

So because the span's work, you'd think we could move them around with relative positioning. Mega fun!

.display-sweet-image-behind span {
   position: relative;
.display-sweet-image-behind span:nth-child(1) {
   top: -20px;
   left: -20px;

The above code would move the first letter up and to the left. But no! Fail! Something about the positioning makes the knockout fail. Double =( =(

As a test, I tried out using margins on those spans, and that IS allowed, so hallelujah, that'll do for fun animation time. Although because these are inline elements, we only get left and right margin, top and bottom have no effect.

.display-sweet-image-behind span:nth-child(1) {
   margin-left: -100px; /* remember this will yank all the letters over this far */


So yeah, do you have to wrap every single letter in a span manually? Nah, that's for suckers. Lettering.js is a jQuery plugin that does exactly that. Literally. You call it on a set of elements and it'll wrap every single letter in a span with a class name referencing its position.


Super simple, super cool. I should have thought of it.

Animate it

The grand goal here is to have the letters animate themselves into place. So here's our markup for the final example:

<div id="poster">
	<h1>Red Sonja</h1>
	<p>Coming 2011</p>

We'll get all the letters into spans with Lettering.js with one line of JavaScript:

$("#poster h1, #poster p").lettering();

For the knockout letters, we'll give them a transition, so that any properties they have that change will animate. Only WebKit browsers will have the knockout, but we might as well have the letters behave the same.

#poster h1 span { 
	-webkit-transition: all 2.5s;
	-moz-transition: all 2.5s;
	-o-transition: all 2.5s;

The classes that Lettering.js applies are char1, char2, etc. So we'll use those classes to apply big margins and kinda kick the letters off the page.

#poster h1 span.char1 { margin-left: -1450px; } 
#poster h1 span.char2 { margin-left: 200px; }
#poster h1 span.char3 { margin-left: 200px; }
#poster h1 span.char5 { margin-left: 1450px; }
#poster h1 span.char6 { margin-left: 200px; }
#poster h1 span.char7 { margin-left: 200px; }
#poster h1 span.char8 { margin-left: 200px; }
#poster h1 span.char9 { margin-left: 200px; }

We're going to go for a short delay before the animation starts. This will give Lettering.js a chance to do it's thing and for the fancy font to load. Also, this is kind of an "experience" effect where waiting a second just makes it more suspenseful.

What we'll do is just wait one second, and then apply a class name to the html element.

setTimeout(function() {$('html').addClass("step-one");}, 1000);

We'll use that class name to override all those margins we set, resetting them back to zero and the letters back in their natural position.

.step-one #poster h1 span { margin: 0; }

The other letters in the demo also use the Lettering.js spans and do their animation via CSS transitions and delayed applied class names, only they aren't knockouts. Because they aren't knockouts (just white type), we can use position: relative.

Let's randomly set their position, then have "Step Two" of the animation happen a few seconds latter, where a class name will kick them back into place.

$("#poster p span").each(function() {  
      top: -(Math.floor(Math.random()*1001)+1500), 
      left: Math.floor(Math.random()*1001)-500,  

setTimeout(function() {$('html').addClass("step-two");}, 3000); 

This time we'll have to use !important rules because jQuery will apply the CSS values with inline styling, and !important is needed to override that.

.step-two #poster p span { 
  top: 0 !important; 
  left: 0 !important; 


In case you are curious, the font in use there is Newcomen available on Typekit.

Even though margin could only handle the left and right margin, the up and down animation I got was from animating the top padding on the parent element. Tricksy.

Oh, and I have no idea if they are really going to remake Red Sonja or not. Seems like a rumor.

View Demo   Download Files


  1. Really awesome, nice tip for under construction landing pages.

  2. All it needs now is a “skip animation” button. ;) In all seriousness though, that looks really nice.

  3. Permalink to comment#

    This one is rather funny, than cool. It drives me back to the flash5 times.
    I don`t know what would be the reaction, after presenting something like this for a client. I guess a good chuckle.

    • You’d tell your client:

      1) It’s plain old semantic HTML. That means it’s search engine friendly and accessible for anybody.

      2) It’s easy to update the text, since it’s literally just web text.

      3) It’s easy to update the background graphic since it’s just a plain ol JPG.

      4) Not every browser gets the same experience, but there are fallbacks for every part of it so it’s decent for everybody.

      Then you and your client would have a great chuckle about how awesome it is and how far the web has come in such a short time.

    • Permalink to comment#

      haha Chris, I love your response here.

    • Permalink to comment#

      I was talking about performance and quality. Crappy frame rate, text as mask with no anti-alias and so on. This is something, you can`t sell with valid code and semantic html.

    • I think it would be a perfectly valid method of doing it if your client wanted an animation like this. I personally would prefer to use this method rather than flash.

  4. Did you consider using transforms for the animation, rather than the setTimeOut approach? The current animation is beyond choppy on the iPad, but I believe a CSS 3D translate transition would be smooth…

    • Sorry – duh, you are using transitions already, I didn’t read the source code closely enough. But you’re not using 3D transitions though, so you’re not getting the hardware acceleration, perhaps hence the choppiness… ?

    • There isn’t anything 3D going on here though… Although I haven’t explored 3D transforms much. If you know more, feel free to expand upon this demo and show us any cool expansions of the idea.

    • Permalink to comment#

      You just use -webkit-transform3d: translate(x,y,0) instead of -webkit-transform:translate(x,y) to get the hardware acceleration (apparently!)

      I keep meaning to make a test page to check if this is the same in iOS4+

  5. bill
    Permalink to comment#

    So we can either do it this way and then create umpteen hacks to account for all the browsers that can’t render it properly, or we can just create a single image and update the image when we need to. That about right?

    • So you’re talking about an animated GIF then? If you can create a new animated GIF faster than I could update this and that is of acceptable file size, sure I guess you could do that. Otherwise this is way more flexible and smaller file size.

      Also, this about possibilities and learning and new technology over specific use case scenarios. Any specific use case scenario needs to be evaluated for what it is.

    • bill
      Permalink to comment#

      Correct, an animated gif or (gasp) Flash. Since you’d need hack for various browsers to get it to work I see no advantage in using the method that you outlined other than a possibly reduced file size.

      I’m all for learning new technology, however this just seems like a weird way to do it.

    • Permalink to comment#

      We might as well just mail out multimedia CD presentations, then we can be sure they can render it properly :)

      This sort of technique only works in modern browsers (Webkit + Firefox 4), so if this was being used in production you just wouldn’t include the animation for legacy browsers. If we continue to write code for the least capable browsers, the web is going to stay the same for years – we need to innovate!

    • bill
      Permalink to comment#

      @Rich, you’re confusing the desire to innovate with the need to develop hacks and workarounds for a technology that isn’t fully developed yet. Using your CD mailing example I should also send out a paper copy if someone doesn’t have a computer.

  6. Permalink to comment#

    Really cool. An Call to action button or entry: ready for photographers landingpage…thanks.

  7. John Seitz
    Permalink to comment#

    It’s amazing to me to see all these relatively “new” web technologies (jquery, css3, etc.) come together to create experiences like this one. Since the time I started learning HTML and CSS 6 years ago the pace at which web technology is expanding seems to be exponential. I almost wish things would slow down a bit so I could catch up.

    It’s increasingly difficult to really define what a web designer is anymore. It could encompass visual design, front-end coding, UX, etc. It used to be a web designer did it all. But as the web has grown more complex we’re finding that separate individuals are being assigned to particular roles. As HTML5 and CSS3 continue to expand I wonder how much more the roles will be broken down to address the increase in knowledge and time necessary to create the web.

  8. Permalink to comment#

    animation is better suits this

  9. Off-topic but of interest: You might want to check your scripting on the home page. I have IE7 at work, and on that browser, the entire main portion of the content fails to display until I scroll down to Latest Screencast. IE also throws an “error on page” message. It’s a restricted system and I can’t get into the settings to do any snooping, otherwise I could perhaps tell you more. It’s a consistent error that happens each time I load the site. It’s entirely possible the problem is on my end, though I do have JS enabled. Just thought I’d give you a heads-up.

    • Permalink to comment#

      Easy fix: Concentrate on work when @ work and have fun when @ home with WebKit-based browsers :)

    • Amit, true enough, but Chris is losing viewers with IE7 and 6 (I have 6 at home for testing, and it fails in that browser, too). Works in 8 and, I presume, 9.

  10. Jquery is nice but your example is not very fluid on my computer.

  11. Nice effect using Jquery. Why don’t Firefox get on board and allow this to work in their browser though. Works fine in Safari.

  12. Works excellent in Safari Browser.

  13. That is fantastic Chris, can’t wait to give it a try :)

    Thanks :)

  14. I think this is just awesome. Stylistic, yet lightweight and very fast to download. I hope to see more stuff like this in the future.

  15. Love it! great work Chris

  16. Great work… beautiful thinking really cool replaces flash with ease…love to see more cool stuffs from u..

  17. Flash will no longer exist.. I guess.

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".