Mastering CSS3: 7 Cool text-shadow Samples You Can’t Miss

Konstantin Kichinsky

We’ve been exploring the basics on how to use CSS3 shadows: box-shadow and text-shadow. Today, we are going to improve our skills and look into how to build some amazing text-shadows.

Some of the ideas for shadows, I found in various tutorials for Photoshop— I was interested in whether or not I could achieve similar effects by using just text-shadow.

Internet Explorer and Windows 8

To try all these samples yourself and express your creativity with the text-shadow, try downloading Internet Explorer 10. All mentioned techniques will also work with metro style apps for Windows 8 built using HTML and JavaScript. May The Shadow be with you!

Arcade Love

In our first sample, we will try to draw some cool, embossed text. We will start with simple lime-colored text:

color: hsl(80, 70%, 55%);

Next, let’s add an embossed effect by adding a few shadows with one-pixel diagonal offsets (note how the shadow’s color is defined compared with the text’s color):

text-shadow: -1px -1px 0 hsl(80, 70%, 35%),
             -2px -2px 1px hsl(80, 70%, 35%);

Now we will add some nice details—a light white, blurred shadow around the text and a dark shadow on the bottom with a soft transition:

text-shadow: 0 0 2px #fff,
             -1px -1px 0 hsl(80, 70%, 35%),
             -2px -2px 1px hsl(80, 70%, 35%),
             -2px -2px 2px hsl(80, 10%, 15%);

Next, let’s add a substrate for our text. To make it happen, we need to expand our shadow (here we are using the fourth parameter of the text-shadow rule—spread-distance):

text-shadow: …
             -3px -3px 0 7px hsl(60, 10%, 65%),
             -4px -4px 0 7px hsl(60, 10%, 65%),
             -5px -5px 0 7px hsl(60, 10%, 65%),
             -6px -6px 0 7px hsl(60, 10%, 65%);

Finally, to place our text on the background, let’s add a dark, blurred shadow to the bottom of the substrate:

text-shadow: …
             -7px -7px 4px 8px hsl(60, 10%, 40%),
             -8px -8px 6px 9px hsl(60, 10%, 55%);

Final result

color: hsl(80, 70%, 55%);
text-shadow: 0 0 2px #fff,
             /* embossed text */
             -1px -1px 0 hsl(80, 70%, 35%),
             -2px -2px 1px hsl(80, 70%, 35%),
             /* transition to substrate */ 
             -2px -2px 2px hsl(80, 10%, 15%),
             /* substrate */ 
             -2px -2px 0 7px hsl(60, 80%, 95%),
             -3px -3px 0 7px hsl(60, 10%, 65%),
             -4px -4px 0 7px hsl(60, 10%, 65%),
             -5px -5px 0 7px hsl(60, 10%, 65%),
             -6px -6px 0 7px hsl(60, 10%, 65%),
             /* shadow for substrate */ 
             -7px -7px 4px 8px hsl(60, 10%, 40%),
             -8px -8px 6px 9px hsl(60, 10%, 55%);

Color Happiness

In the second sample, we will reuse some ideas from the first one: we a going to build multiple, colorful substrates, making a pyramid of them. We will start with very simple pink text:

color: hsl(330, 100%, 50%);

First of all, let’s make it embossed. This time our shadow looks to the bottom and is really small, so I can reduce the number of applied rules by omitting intermediate, one-pixel offsets—but in the case of a diagonal shadow, such an approach would result in an aliasing effect. I will also add some blurring to soften the transition to the next substrate:

text-shadow: 0 2px 0 0px hsl(330, 100%, 25%),
             0 3px 2px 0px hsla(330, 100%, 15%, 0.5);

Next, let’s add one more expanded substrate with a different hue value (note that I’m changing only vertical offset, hue, and spread-distance):

text-shadow: 0 2px 0 0px hsl(330, 100%, 25%),
             0 3px 2px 0px hsla(330, 100%, 15%, 0.5),
             0 3px 0 3px hsl(350, 100%, 50%),
             0 5px 0 3px hsl(350, 100%, 25%),
             0 6px 2px 3px hsla(350, 100%, 15%, 0.5);

Now we just need to repeat the same trick a few more times, increasing the size of the substrates, and moving the hue in the right direction:

text-shadow: …
             0 6px 0 9px hsl(20, 100%, 50%),
             0 8px 0 9px hsl(20, 100%, 25%),
             0 9px 2px 9px hsla(20, 100%, 15%, 0.5),
             …
             0 15px 0 45px hsl(90, 100%, 50%),
             0 17px 0 45px hsl(90, 100%, 25%),
             0 17px 2px 45px hsla(90, 100%, 15%, 0.5);

Final result

color: hsl(330, 100%, 50%);
text-shadow: 0 2px 0 0px hsl(330, 100%, 25%),
             0 3px 2px 0px hsla(330, 100%, 15%, 0.5),
             /* next */
             0 3px 0 3px hsl(350, 100%, 50%),
             0 5px 0 3px hsl(350, 100%, 25%),
             0 6px 2px 3px hsla(350, 100%, 15%, 0.5),
             /* next */
             0 6px 0 9px hsl(20, 100%, 50%),
             0 8px 0 9px hsl(20, 100%, 25%),
             0 9px 2px 9px hsla(20, 100%, 15%, 0.5),
             /* next */
             0 9px 0 18px hsl(50, 100%, 50%)
             0 11px 0 18px hsl(50, 100%, 25%),
             0 12px 2px 18px hsla(50, 100%, 15%, 0.5),
             /* next */
             0 12px 0 30px hsl(70, 100%, 50%),
             0 14px 0 30px hsl(70, 100%, 25%),
             0 15px 2px 30px hsla(70, 100%, 15%, 0.5),
             /* next */
             0 15px 0 45px hsl(90, 100%, 50%),
             0 17px 0 45px hsl(90, 100%, 25%),
             0 17px 2px 45px hsla(90, 100%, 15%, 0.5);

Chocolate

The third sample I built while experimenting with alternating shadows starts with simple, brown text:

color: hsl(20, 100%, 20%);

The first step is to implement a classic 3D text effect:

text-shadow: -1px 1px 0 0 hsl(20, 100%, 16%),
              -2px 2px 0 0 hsl(20, 100%, 16%),
              -3px 3px 0 0 hsl(20, 100%, 16%),
              -4px 4px 0 0 hsl(20, 100%, 16%),
              -5px 5px 0 0 hsl(20, 100%, 16%),
              -6px 6px 0 0 hsl(20, 100%, 16%);

Next, I decided to darken my shadows by decreasing the lightness, and to add some space between the shadows by increasing the diagonal offset:

text-shadow: -0px 0px 0 0 hsl(20, 100%, 16%),
               -2px 2px 0 0 hsl(20, 100%, 14%),
               -4px 4px 0 0 hsl(20, 100%, 12%),
               -6px 6px 0 0 hsl(20, 100%, 10%),
               -8px 8px 0 0 hsl(20, 100%, 8%),
               -10px 10px 0 0 hsl(20, 100%, 6%);

The next step is to contract the shadows. By using contraction, you can reduce the shadow to just some pieces of original symbols (it also depends on the font, font size and other attributes). As a result, you will get a ragged shadow effect. Also, notice that as diagonal offsets and spread-distances differ for each of the shadows, we get a light twisting effect:

text-shadow: -0px 0px 0 0 hsl(20, 100%, 16%),
             -2px 2px 0 -1px hsl(20, 100%, 14%),
             -4px 4px 0 -2px hsl(20, 100%, 12%),
             -6px 6px 0 -3px hsl(20, 100%, 10%),
             -8px 8px 0 -4px hsl(20, 100%, 8%),
             -10px 10px 0 -5px hsl(20, 100%, 6%);

Let’s soften our shadows a little bit. By using blur-radius and color, we can add some intermediate lines:

text-shadow: -0px 0px 1px 0 hsl(20, 100%, 16%),
             -2px 2px 2px -1px hsl(20, 100%, 14%),
             -4px 4px 2px -2px hsl(20, 100%, 12%),
             -6px 6px 3px -3px hsl(20, 100%, 10%),
             -8px 8px 2px -4px hsl(20, 100%, 8%),
             -10px 10px 2px -5px hsl(20, 100%, 6%);

Finally, after playing with this sample for a few more minutes, I achieved the following result…

Final result

color: hsl(20, 100%, 20%);
text-shadow: 0 0 1px hsl(20, 100%, 18%),
             -1px 1px 0 hsl(20, 100%, 16%), 
             -2px 2px 2px -1px hsl(20, 100%, 14%), 
             -4px 4px 2px -2px hsl(20, 100%, 12%),
             -6px 6px 3px -3px hsl(20, 100%, 10%),
             -8px 8px 2px -4px hsl(20, 100%, 9%),
             -10px 10px 3px -5px hsl(20, 100%, 8%),
             -12px 12px 2px -6px hsl(20, 100%, 7%),
             -14px 14px 2px -7px hsl(20, 100%, 6%),
             -15px 15px 2px -8px hsl(20, 100%, 5%), 
             -15px 15px 0 -8px hsla(20, 50%, 10%, 0.25);

Cream Cake

In the fourth sample, we build a cream-text effect for some cake. Here’s the text:

color: hsl(35, 100%, 30%);
background: hsl(35, 60%, 80%);

Let’s start with blurring. I added two shadows: the first one (upper) has the same hue value as the text, but with less saturation, and the second one (lower) is more blurred, lighter, and semi-transparent. I also moved the lower shadow’s hue value towards red:

text-shadow: 0 0 2px 1px hsl(35, 70%, 30%),
             0 0 4px 4px hsla(30, 100%, 55%, 0.5);

Now let’s add some cream-color substrate (the hue value is moved towards yellow and the lightness is increased):

text-shadow: …
             -1px 1px 2px 7px hsl(45, 60%, 95%);

On the next step, we should add some volume to the substrate: I added a new shadow with diagonal offset of the same color as the text, but less saturated. Note that this shadow is less expanded than the substrate (4px versus 7px):

text-shadow: …
             -3px 3px 1px 4px hsl(35, 70%, 30%);

And one last step: blurring substrate to soften the transition to the background:

text-shadow: …
             -3px 3px 4px 8px hsla(30, 90%, 55%, 0.5);

Final result

color: hsl(35, 100%, 30%);
background: hsl(35, 60%, 80%);
text-shadow: 0 0 2px 1px hsl(35, 70%, 30%),
             /* transition to substrate */
              0 0 4px 4px hsla(30, 100%, 55%, 0.5),
             /* substrate */
             -1px 1px 2px 7px hsl(45, 60%, 95%),
             /* adding volume */
             -3px 3px 1px 4px hsl(35, 70%, 30%),
             /* transition to background */
             -3px 3px 4px 8px hsla(30, 90%, 55%, 0.5);

Plastic

I was playing with the last one thinking, “What I can do on top of it…?” As in many other samples, final results depends on both the text itself (size, font and so on) and the applied shadow effects. In my fifth sample, I’m using the CabinSketch font. So here is what we have—it is just text without any special effects:

color: hsl(65, 60%, 20%);
background: hsl(65, 60%,95%);

First of all, I added some blurring around the text (notice that the shadow is lighter than the text, and as a result the text looks brighter and more saturated):

text-shadow: 0 0 3px 2px hsl(65, 60%,75%);

Next, let’s add some outlining with blurring effect (note that I’m using expansions and decreased lightness):

text-shadow: 0 0 3px 2px hsl(65, 60%,75%),
             0 0 1px 9px hsl(65, 60%, 20%);

Yeah, it looks too dark—I will add an intermediate shadow to lighten my text:

text-shadow: 0 0 3px 2px hsl(65, 60%,75%),
             0 0 1px 5px hsl(65, 60%,95%),
             0 0 1px 9px hsl(65, 60%, 20%);

Now for the most interesting step. Actually, I don’t need the full outlining (substrate), just some pieces. To hide excess details, I will draw a few shadows on top of the substrate. These shadows are smaller in size, but have bigger diagonal offsets:

text-shadow: 0 0 3px 2px hsl(65, 60%,75%),
             0 0 1px 5px hsl(65, 60%,95%),
             6px 6px 4px 7px hsl(65, 60%,95%),
             -4px -6px 4px 6px hsl(65, 60%,95%),
             0 0 1px 9px hsl(65, 60%, 20%);

You may also try softening some details.

Final result

color: hsl(65, 60%, 20%);
background: hsl(65, 60%,95%);
text-shadow: 0 0 3px 2px hsl(65, 60%,75%),
            /* light substrate */
             0 0 1px 5px hsl(65, 60%,95%),
            /* blurring */
             0 0 4px 4px hsla(65, 100%, 30%, 0.4),
            /* cutting substrate pieces */
            6px 6px 4px 7px hsl(65, 60%,95%),
            -4px -6px 4px 6px hsl(65, 60%,95%),
            /* dark outlining */
             0 0 1px 9px hsl(65, 60%, 20%);

Painting

The following two samples will offer you some techniques for using transparency. Think about it: how would you use the text-shadow to draw inside the text? Actually, you can’t use the text-shadow to draw inner shadows. All the shadows you apply to the text are combined into a stack, and are drawn one on top of another. Then the text is drawn on top of all of them. So you need to make the text disappear somehow… and to make it happen you can just make the text transparent!

color: transparent;
background: hsl(0, 75%,45%);

Now the way is clear. I’m going to draw with the white color (so the only thing that really matters is the 100% lightness). To draw something inside the text, just decrease the size of shadow:

text-shadow: 3px 3px 1px -8px hsla(0, 60%, 100%, 0.75);

Let’s add some more details by varying transparency, offset and size:

text-shadow: 3px 3px 1px -8px hsla(0, 60%, 100%, 0.75),
             -1px -1px 1px -4px hsla(0, 60%, 100%, 0.65),
             1px 1px 1px -4px hsla(0, 60%, 100%, 0.65);

To strengthen the shape, you can add an expanded and blurred shadow:

text-shadow: …
             0 0 1px 2px hsla(0, 60%, 100%, 0.65);

You may add extra details if you wish.

Final result

color: transparent;
background: hsl(0, 75%,45%);
text-shadow: 3px 3px 1px -8px hsla(0, 60%, 100%, 0.75),
             -1px -1px 1px -4px hsla(0, 60%, 100%, 0.65),
             1px 1px 1px -4px hsla(0, 60%, 100%, 0.65),
             /* background */
             0 0 1px 2px hsla(0, 60%, 100%, 0.65),
             * additional details */
             -3px -3px 1px 2px hsla(0, 60%, 100%, 0.25),
             3px 3px 1px 2px hsla(0, 60%, 100%, 0.25);

Up & Down

And the final sample! I’m going to continue playing with transparency. I will start with white text (selected just to make it visible):

color: transparent;

First of all, let’s add a classic 3D text effect (you can play with the transparency here). Note the increased lightness value in the middle shadow—I found it a nice way to emphasize the volume (try to increase the lightness to make it more visible):

text-shadow: 1px -1px hsla(0, 0%, 30%, .6),
             2px -2px hsla(0, 0%, 30%, .7),
             3px -3px hsla(0, 0%, 32%, .8),
             4px -4px hsla(0, 0%, 30%, .9),
             5px -5px hsla(0, 0%, 30%, 1.0);

Now to add more volume, I will add a shadow on top, repeating the form of the original text:

text-shadow: 0px 0px hsla(0, 0%, 50%, .5),
             1px -1px hsla(0, 0%, 30%, .6),
             …

Finally, similar to the bottom part, I will add upper 3D shadows, but with more transparency and more lightness (to make this part sharper, the uppermost shadow is drawn with less transparency):

text-shadow: -4px 4px hsla(0, 0%, 70%, .4),
             -3px 3px hsla(0, 0%, 60%, .2),
             -2px 2px hsla(0, 0%, 70%, .2),
             -1px 1px hsla(0, 0%, 70%, .2),
             …

Final result

color: transparent;
text-shadow: -4px 4px hsla(0, 0%, 70%, .4),
             -3px 3px hsla(0, 0%, 60%, .2),
             -2px 2px hsla(0, 0%, 70%, .2),
             -1px 1px hsla(0, 0%, 70%, .2),
             0px 0px hsla(0, 0%, 50%, .5),
             1px -1px hsla(0, 0%, 30%, .6),
             2px -2px hsla(0, 0%, 30%, .7),
             3px -3px hsla(0, 0%, 32%, .8),
             4px -4px hsla(0, 0%, 30%, .9),
             5px -5px hsla(0, 0%, 30%, 1.0);

Note

The text-shadow property discussed in this article is defined in the CSS3 Text module which is currently in the Working Draft status. While it seems to be quite stable, it still can change in details.

Spread-distance value for text-shadows is currently defined in the Editor’s Draft for CSS Text Level 4..

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Vincent

    Nice man! Thanks for these.

  • http://portfolio@geekoutcast.net Steve

    Wow, this is some great stuff. I had already been playing with the various css3 effects to avoid using graphics as much, but you’re using techniques here I hadn’t seen before. Love it!

  • Clint Fern

    Sorry Sitepoint, I can miss these. IE10 only (how minor an audience is that?) – also as far as I can tell not part of the CSS3 specifications.

    This looks to be an example of a Microsoft proprietary tag (haven’t they learnt?) and it damages the Sitepoint brand to be involved if this is the case.

    • Nick Body

      How do you figure that to be IE10 only? http://caniuse.com/#search=text-shadow

      But yeah, as with all fancy, shiny things it’s best done with moderation

    • http://blogs.msdn.com/b/kichinsky Konstantin Kichinsky

      Clint, you are almost right, except one thing: the text-shadow property is defined in the CSS3 Text module, but the fourth length parameter (spread distance) is not any more a part of that spec and was moved to the next level — css4 text. You can read my note on that in previous article: http://www.sitepoint.com/mastering-css3-text-shadows/

      This kind of change is normal and is because of the standardization process, and does not be an example of something proprietary.

  • http://www.mainstreethost.com Pete

    Great Post!! I’ve been looking for examples and you pretty much showed everything in this post. thanks again!

  • tomByrer

    Where is it in the spec for Spread-distance please? At http://dev.w3.org/csswg/css4-text/#text-shadow0 I can only find:
    Value: none | [ {2,3} && ? ]#

    Computed value: a color plus three absolute s

    • http://blogs.msdn.com/b/kichinsky Konstantin Kichinsky

      Tom, here is it:
      Value: none | [, ] *
      is the same as defined for the ‘box-shadow’ property except that the ‘inset’ keyword is not allowed.

      For additional details please look at the csswg discussion list (www-style) on w3c. And as it is still a draft it continues to be a subject to change.

      • http://blogs.msdn.com/b/kichinsky Konstantin Kichinsky

        Correction:
        Value: none | [, ] *

      • http://blogs.msdn.com/b/kichinsky Konstantin Kichinsky

        Arrr,
        Value: none | [shadow, ] * shadow

      • tomByrer

        I’m sorry Konstantin, but I still do not see it in the spec; as the spec clearly reads (as of the ‘W3C Working Draft 19 January 2012′, sorry if my link goes to an older version)
        “Value: none | [ {2,3} && ? ]#
        Initial: none
        Applies to: all elements
        Inherited: yes
        Percentages: N/A
        Media: visual
        Computed value: a color plus three absolute s

        This property accepts a comma-separated list of shadow effects to be applied to the text of the element. Values are interpreted as for ‘box-shadow’. [CSS3BG] The shadow is applied to all of the element’s text as well as any text decorations it specifies.

        The shadow effects are applied front-to-back: the first shadow is on top. The shadows may thus overlay each other, but they never overlay the text itself. The shadow must be painted at a stack level between the element’s border and/or background, if present, and the elements text and text decoration. UAs should avoid painting text shadows over text in adjacent elements belonging to the same stack level and stacking context. (This may mean that the exact stack level of the shadows depends on whether the element has a border or background: the exact stacking behavior of text shadows is thus UA-defined.)

        Unlike ‘box-shadow’, text shadows are not clipped to the shadowed shape and may show through if the text is partially-transparent. Like ‘box-shadow’, text shadows do not influence layout, and do not trigger scrolling or increase the size of the scrollable area.

        A number of less-stable features have been deferred to Level 4:

        the spread radius on ‘text-shadow’ ”

        The Editor’s Draft we both linked to before is dated before, 6 January 2012.

        So it seems that the px inputs are capped at 3, no room for the 4th “spread” input. The only mention of “spread” for text-shadow states that it has been put off… or am I reading this wrong?

        ==

        Either way, we are still talking about pre-DRAFT, for an extra value that is ONLY supported by a BETA of a single browser. Firefox Dekstop Nightly (as of this writing) still does not support text-shadow spread, & I’m sure desktop Chrome is the same.

        It is fun to see what browsers *perhaps can do* via CSS, & I hope that IE10′s ‘spread’ does make it into the final spec version, & implemented with all the other browsers soon. But we clearly are not near that point yet. Until ‘spread’ is clearly put into the spec, I’d avoid mentioning it outside of a fun-playground experiment. Please mark it more clearly as such, perhaps at the top of the articles:
        ** CAUTION: Experimental properties for IE 10 beta ONLY **

      • http://blogs.msdn.com/b/kichinsky Konstantin Kichinsky

        Actually, it is an interesting story on how some web standards can evolve thru the time.

        Originally the text-shadow property was defined in the CSS 2 and then moved to the Level 3 because of the lack of implementations.

        2007 — the CSS3 Text module (http://www.w3.org/TR/2007/WD-css3-text-20070306/#text-shadow) the text-shadow was defined *in place* with 3 length parameters.

        Some three and half years later in the October’10 (http://www.w3.org/TR/2010/WD-css3-text-20101005/#text-shadow) the definition was updated and started to point to the definition of the box-shadow, which already had the spread distance parameter:

        This property accepts a comma-separated list of shadow effects to be applied to the text of the element. *shadow* is the same as defined for the ‘box-shadow’ property except that the ‘inset’ keyword is not allowed.

        Next for more than 2 years the spread distance was indirectly present in the draft for the CSS3 Text but had no any implementation support in browsers unless it was finally implemented in IE10 Platform Preview.

        The latest version for CSS3 Text with spread distance was published in September last year: http://www.w3.org/TR/2011/WD-css3-text-20110901/#text-shadow

        At that moment there was also a discussion in the bugzilla for firefox and they desided to wait with implementation until the CSS3 Text will reach the CR.

        but…

        In January’12 (if I’m not mistaken) there was a discussion in the CSS WG on how to quicker move the spec forward to the CR and one of the decisions made was to use the definition similar to the one that was previously used in CSS2 and thus way the spread distance was excluded from the present spec draft on the L3 and moved to the L4 (editors draft as for now).

        That is the story behind the spread distance or at least my understanding of this story. When the IE team implemented text-shadow property in PP-version for IE10 it was definetely with 4 length parameters in the actual spec draft of the CSS3 Text. Today, as the spec changed, you are right — it looks like a proof of concept for the future.

        I also discussed this issue in my article on mastering text-shadows (http://www.sitepoint.com/mastering-css3-text-shadows/).

  • http://www.mymmcloud.com Zaw Myo Htet

    What a nice one!

  • http://www.paulund.co.uk Paul

    Multiple text shadow is such a good feature can create some great designs.

  • http://solo83331.com jason foley

    Ha, I thought that was the whole reason.!

    [img]http://i1105.photobucket.com/albums/h355/1bbcd5/track.jpg[/img]

  • http://crowdogs.com Peter Schreiner

    Simply Too Cool! You’ll make a designer out of me yet!