Fun With Blurred Text

Published by Chris Coyier

Making text blurry is pretty easy. Just make the color transparent and set a text-shadow.

.blurry-text {
   color: transparent;
   text-shadow: 0 0 5px rgba(0,0,0,0.5);
}

That's dangerous though, because there are browsers that support color but not text shadow, so the end result would be totally invisible text. Of course, the solution is to feature detect and only apply this effect if you are in a browser that supports it:

.textshadow .blurry-text {
   color: transparent;
   text-shadow: 0 0 5px rgba(0,0,0,0.5);
}

The color of the shadow is the only thing visible, so make sure it has enough contrast enough to be seen.

See the Pen Fun with Blurred Text by Chris Coyier (@chriscoyier) on CodePen.

Thems the basics. Now let's do some fun stuff.

By The Letter

Using Lettering.js, we can inject spans into a word. So..

<h2>Smokemonster</h2>

becomes

<h2>
  <span>S</span>
  <span>m</span>
  <span>o</span>
  <!-- you get the idea -->
</h2>

Now instead of of having to apply the shadow on the entire word, we can do it letter-by-letter. Let's make the blur zoom across the text like a crazy Eko-killing smoke monster.

First we'll make a keyframe animation1 which animates from solid to blurry. For the sake of demo, this we're using the -webkit- prefix, but you should use all the prefixes.

@-webkit-keyframes blackblur {
  from { text-shadow: 0 0 72px black; color: transparent; }
  to   { text-shadow: 0;              color: black;       }
}

Now we can call that animation on every single letter. The further the letter along in the word2, the longer the delay before it starts.

.smokemonster span:nth-of-type(1)  { -webkit-animation: blackblur 2s       1 alternate; }
.smokemonster span:nth-of-type(2)  { -webkit-animation: blackblur 2s 0.1s  1 alternate; }
.smokemonster span:nth-of-type(3)  { -webkit-animation: blackblur 2s 0.15s 1 alternate; }
.smokemonster span:nth-of-type(4)  { -webkit-animation: blackblur 2s 0.2s  1 alternate; }
.smokemonster span:nth-of-type(5)  { -webkit-animation: blackblur 2s 0.25s 1 alternate; }
.smokemonster span:nth-of-type(6)  { -webkit-animation: blackblur 2s 0.3s  1 alternate; }
.smokemonster span:nth-of-type(7)  { -webkit-animation: blackblur 2s 0.35s 1 alternate; }
.smokemonster span:nth-of-type(8)  { -webkit-animation: blackblur 2s 0.4s  1 alternate; }
.smokemonster span:nth-of-type(9)  { -webkit-animation: blackblur 2s 0.45s 1 alternate; }
.smokemonster span:nth-of-type(10) { -webkit-animation: blackblur 2s 0.5s  1 alternate; }
.smokemonster span:nth-of-type(11) { -webkit-animation: blackblur 2s 0.55s 1 alternate; }
.smokemonster span:nth-of-type(12) { -webkit-animation: blackblur 2s 0.6s  1 alternate; }

Now that's awfully repetitive, but hey, that's the deal with CSS sometimes. It's not really a programming language...

Getting Programatic

Let's say we had an unknown number of letters we wanted to deal with individually. Or we wanted to programmatically decide what color to use for the shadow. Or we wanted to randomly choose the blur level. CSS isn't suited for any of these things, we'll want to use JavaScript instead. As usual around here, I'm going to lean on jQuery.

jQuery can SET a text shadow like this:

$(".blur").css({
  'text-shadow': '2px 2px 5px green'
});

Luckily, text-shadow doesn't come with a bunch of vendor prefixes to deal with. But still, we're a little little hamstrung here. What if we just want to set the offset, blur, or color? There isn't specific CSS properties for those things. We'd have to repeat the whole string with repetitive values to make a change. Not the end of the world, but what's worse, we can't animate!

That's where the jquery-cssHooks project comes in. It extends jQuery to be able to handle individual parts of complex CSS properties like text-shadow, box-shadow, border-image, transform, etc.

Once we load up the scripts we need (order is important)...

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="js/color.js"></script>
<script src="js/textshadow.js"></script>

...we now have the ability to get/set/animate individual parts of the text-shadow.

$(".blur").css({
  'textShadowColor': 'red'
});

$(".blur").animate({
  'textShadowBlur': 50
});

Fancy!

Let's get our random on and animate random letters to random blur values with random color saturation.

var text = $("#some-word"),
    // assuming lettering() has already been called on it
    numLetters = text.find("span").length; // how many letters?

function randomBlurize() {

  text
    // pick random letter
    .find("span:nth-child(" + (Math.floor(Math.random()*numLetters)+1) + ")")
    .animate({
      'textShadowBlur': Math.floor(Math.random()*25)+4,
      'textShadowColor': 'rgba(0,100,0,' + (Math.floor(Math.random()*200)+55) + ')'
    });

// Call itself recurssively
setTimeout(randomBlurize, 100);

} // Call once
randomBlurize();

Funny how much easier animating text-shadow is in CSS. But doing it this way is cool too as it has all those programatic advantages.

View Demo   Download Files   Play on CodePen


1 While keyframe animations are WebKit only right now, rumor has it they might make Firefox 5. Update July 2012: keyframe animations are in all major browsers now and need the prefixes: -webkit-, -moz, -ms-, and -o-.

2 Notice we are using :nth-of-type here. I generally find that way more useful than :nth-child. Especially in this case where we wouldn't want other tags screwing up the flow.