HTML5 INSIGHT EN

We have discussed previously some of the new features defined in the CSS3 Backgrounds and Borders module, while talking about the art of shadows. Today we will focus on another interesting feature — how to use multiple backgrounds with CSS3.

Backgrounds composition

There are many reasons why you may need to create a composition of multiple images to build you background. I think the most important are the following ones:

  • to reduce the bandwidth usage if the sum of sizes of separate images is less than the size of an image with merged layers (especially if your image contains repeating patterns), and
  • to provide a way for independent manipulations on different layers (for example if you are going to implement some parallax effect).

I believe you may have other reasonable arguments. :)

Classic approach

So we need to build a multi-layered background by placing some images on top of others. How this problem is usually solved? It is really easy: just create a container (like a div element) for each of the images you have and add a background for it using a CSS rule. Next you insert one container into another or place them in a row and apply corresponding positioning CSS rules. I have here a simple sample:

<div class="sample1">
    <div class="sea">
        <div class="mermaid"><div class="fishing"></div></div>                
        <div class="fish"></div>
    </div>
</div>

The “fishing” class if inside of the “mermaid” class only for demo purposes.

And here we have some CSS styles:

.sample1 .sea, .sample1 .mermaid, .sample1 .fishing {
    height:300px;
    width:480px;
    position: relative;
}
            
.sample1 .sea {
    background: url(media/sea.png) repeat-x top left;          
}
            
.sample1 .mermaid {
    background: url(media/mermaid.svg) repeat-x bottom left;
}
        
.sample1 .fish {
    background: url(media/fish.svg) no-repeat;
    height:70px;
    width:100px;
    left: 30px;
    top: 90px;
    position: absolute;
}
            
.sample1 .fishing {
    background: url(media/fishing.svg) no-repeat top right 10px;
}

Result:

Sample 1. Classic nested divs

In this sample I have three nested divs with background and one more neighbor “fish”-div. You may imagine that the fish can be animated using javascript or css3 transitions or animations.

Note, for the “fishing” class I’m using the new background positioning syntax, also defined in CSS3 (I marked it with yellow). But as for now it is supported only by IE9+ and Opera 11+, but does not work in Firefox 10 or Chrome 16. So the users of the last two can not catch the fish :(

Let’s continue. Is it possible to simplify this composition?

Multiple backgrounds

This is when the multiple backgrounds come to the scene. This feature allows you to add more than one background at once and to the same element. Here is how it looks like:

<div class="sample2">
    <div class="sea">                     
        <div class="fish"></div>
    </div>
</div>

And styles:

.sample2 .sea {
    height:300px;
    width:480px;
    position: relative;
    background-image:  url("media/fishing.svg"), url("media/mermaid.svg"), url("media/sea.png");  
    background-position: top right 10px, bottom left, top left;
    background-repeat: no-repeat, repeat-x, repeat-x ;
}
            
.sample2 .fish {
    background: url("media/fish.svg") no-repeat;
    height:70px;
    width:100px;
    left: 30px;
    top: 90px;
    position: absolute;
}

To define multiple backgrounds you should use the background-image rule by enumerating your images comma-separated. You may also use other rules to set a position, repeating mode and other attributes to each of the images — just write up them also using a comma-separated list for the corresponding rule. Note the order of images: they are listed left to right starting with the uppermost one and ending with the lowest one.

The result is 100% identical:

Sample 2. Using multiple backgrounds

In one rule

If you don’t need you fish to swim in an independent block the whole background can be written in one simple rule:

<div class="sample3">
    <div class="sea"></div>
</div>

Styles:

.sample3 .sea {
    height:300px;
    width:480px;
    position: relative;
    background-image:  url("media/fishing.svg"), url("media/mermaid.svg"), url("media/fish.svg"), url("media/sea.png");  
    background-position: top right 10px, bottom left,  30px 90px, top left;
    background-repeat: no-repeat, repeat-x ;
}

I’m not showing the same picture one more time but trust me — it is equal to the two images above. Pay you attention to the styles one more time and especially on the background-repeat rule. According to the spec if a part of the list is omitted UA (browser) should repeat present list to fill the rest.

In our case it equal to the following definition:

background-repeat: no-repeat, repeat-x, no-repeat, repeat-x;

Shorter version

If you remember the CSS 2.1 it is possible to describe a background image in a one short “background”-rule. What about multiple backgrounds? Actually you also can use the “background”-rule for multiple backgrounds:

.sample4 .sea {
    height:300px;
    width:480px;
    position: relative;
    background: url("media/fishing.svg") top right 10px no-repeat, 
                url("media/mermaid.svg") bottom left repeat-x,
                url("media/fish.svg") 30px 90px no-repeat,
                url("media/sea.png") repeat-x;                
            }

But note that you can’t easily ommit arguments unless the values are equal to the default ones. Also if you would like to define the color of background you should do it in the latest layer.

Dynamic images

Here is what we already know: if you background is mostly static — it may depend on the container size (i.e. if you are using % length so that some layers will shift on resizing window) — than the magic of multiple backgrounds seems to be useful as it really simplifies the page structure. But what if you need to animate some of the layers using javascript (move, rotate and so on)?

I have a real life sample — the dandelion theme on the Yandex website (Russian search provider, YNDX):

Yandex

If you look in to the source code (press F12 in your IE to open devtools) you will find a code like that one:

<div class=b-skin-bg sizcache="272" sizset="0">
	<div class=b-fluff-bg sizcache="272" sizset="0">
		<div class=b-fluff__sky sizcache="272" sizset="0">
			<div style="background-position: 3244px 0px" class=b-fluff__cloud></div>
			<div style="width: 1200px" class=b-max-width sizcache="214" sizset="0">
				<div class=b-fluff__placeholder sizcache="302" sizset="0">
					<div style="bottom: 105px; display: none; left: 940px" class="b-fluff__item b-fluff_item_3" jQuery1328289994769="30"></div>
					<div style="bottom: 50px; display: none; left: 879px" class="b-fluff__item b-fluff_item_3" jQuery1328289994769="31"></div>
					<div style="bottom: 105px; display: none; left: 940px" class="b-fluff__item b-fluff_item_3" jQuery1328289994769="32"></div>
					...
				</div>
			</div>
		</div>
	</div>
</div>

The divs with classes “b-fluff-bg”, “b-fluff__cloud” и “b-fluff__item” have the css rules applied adding overlaying background images. The background with cloud is scrolled from left to right, and the backgrounds with dandelion seeds are flying across the screen.

Is it possible to rewrite such composition using css3 multiple backgrounds? Actually yes, but only if 1) it is supported in all target browsers and 2) continue reading ;)

How can we make our multiple backgrounds more dynamic? Internally the browser parses every “background” rule into separate “background-*” rules for each of the attributes. It is very useful if you need to change only one of the attributes. For example you can use “background-position” rule to shift your images. But there are some penalties while dealing with multiple backgrounds: if you are going to move only one layer you still need to rewrite this rule for all layers.

To animate our sea background we can use the following js-code:

$(document).ready(function() {
    var sea = $(".sample5 .sea")[0];
    var fishesX = 30;
    var fishesY = 90;
    var fishX = 0;
    var fishY = 0;
    var mermaidX = 0;
    var t = 0;

    function animationLoop() {
        fishesY = 90 + Math.floor(30 * Math.sin(t++ / 180.0));
        if(--fishesX < 0) fishesX = 480;
        mermaidX += 0.5;
        if(mermaidX > 480) mermaidX = 0;
        fishY = -10 + (10 * Math.cos(t * 0.091));
        fishX = 10 + (5 * Math.sin(t * 0.07));

        sea.style.backgroundPosition = "top " + fishY + "px right " + fishX + "px, " + mermaidX + "px bottom," + fishesX + "px " + fishesY + "px, top left";

        window.requestAnimFrame(animationLoop);
    }
    animationLoop();
});

where

window.requestAnimFrame = (function() {
    return 
        window.requestAnimationFrame || 
        window.msRequestAnimationFrame ||
        window.mozRequestAnimationFrame || 
        window.oRequestAnimationFrame || 
        window.webkitRequestAnimationFrame || 
        (function(callback) { window.setTimeout(callback, 1000 / 60); });
})();

Result (video):

Sample 5. Animating

You may also use CSS3 Transitions or Animations but it is a good topic for separate discussion.

Parallax and interactivity

Finally using similar technics you can easily add some parallax effects or other interaction effects for you background:

Multiple backgrounds are useful in such scenarios and while we are talking only about backgrounds, not the content, using them is definitely a good way to not pollute the html-code with complex unnecessary elements. But as I said there are some penalties if you need to build a complex and dynamic background: you cannot access a separate layer by id, class or any other parameter. You should remember the order of layers in your code and to change an attribute for just one layer you will need to build a string describing this attribute for all the layers you have. To update one layer you need to update the whole composition:

sea.style.backgroundPosition = "top " + fishY + "px right " + fishX + "px, " + mermaidX + "px bottom," + fishesX + "px " + fishesY + "px, top left";

I’m sure it is possible to build a nice and useful js-library which will virtualize all these layers and provide easy way to change attributes for a separate layer keeping clean your html-code and the DOM.

Compatibility

All modern browsers including IE9+ support multiple backgrounds. You may also use some tools like Modernizr to provide some level of compatibility for older browsers, i.e. by providing alternate background. As Chris Coyier wrote in his article on the stacking order of multiple backgrounds you can use the following approach:

.multiplebgs body {
   /* Awesome multiple BG declarations that transcend reality and impress chicks */
}
.no-multiplebgs body {
  /* laaaaaame fallback */
}

If you are confused with using javascript to provide backward compatibility for the new CSS3 rules you can just define background property twice (but this approach may result unnecessary downloads in modern browsers depending on how they process such rules):

/* multiple bg fallback */
background: #000 url(...) ...;
/* Awesome multiple BG declarations that transcend reality and impress chicks */
background url(...), url(...), url(...), #000 url(...);

And finally if you wish to know it: yes you can use multiple backgrounds in you Windows 8 metro style apps built with html and javascript.

p.s. Check also this phenomenal article about the Cicada Principle by Alax Walker.

Note

CSS properties discussed in this article are defined in the CSS3 Backgrounds and Borders module, which is currently in the Working Draft status. Meanwhile it seems to be stable it still can change in details. I will hopefully do my best to keep this article up to date to reflect latest spec changes, but if you find anything outdates, please ping me in twitter — @kichinky.

In the previous two parts we learned the basics on how to use CSS3 shadows: box-shadow and text-shadow. Today we are going to improve our skills and will look into how to build some amazing text-shadows.

To be honest with you I need to say that some of the ideas for shadows (two or three) I found in various tutorials for Photoshop — and I was interested whether I can achieve similar effects by using just text-shadow.

Also I need to warn you that some of the samples you will find here (ok, most of them) may not work in your favorite browser because it does not support the spread-distance for text-shadows (see also the discussion on using spread in previous part). But you can always install the latest platform preview version of the Internet Explorer 10 to try all new features yourself.

And… also I really would like to draw your attention on how useful are hsl() and hsla() functions while working with multiple shadows. You can easily change lightness and saturation without affecting hue that is very powerful while dealing with shadows.

Arcade Love

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

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

Next let’s add some embossed effects by adding few shadows with 1px diagonal offset (note how the shadows color is defined comparing with the text 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 to soft transitions:

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 — spray-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 lets add a dark blurred shadow on 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

Arcade Love

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 of the first one: we a going to build multiple colorful substrates making a pyramid of them. We will start with a 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 a number of applied rules by omitting intermediate 1px offsets — but on case of diagonal shadow such approach will result an aliasing effect. Also I will add some blurring to soft 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 few more times increasing the size of substrates and moving the hue in a 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 Happiness

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. As usually lets start with a 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 dark my shadows by decreasing the lightness and to add some space between the shadows by increasing 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 note that as diagonal offsets and spread-distances differ for each of the shadows as a result 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 soft a little bit our shadows (also by using various blur-radius and color you 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 some more minutes I got the following result…

Final result

Chocolate

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 will build a cream-text effect for some cake. Just text:

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

Let’s start with blurring. I added two shadows: the first one (upper) is made with the same hue-value as the text, but with less saturation, and the second one (lower) is more blurred, more lighted and half-transparent and I also moved its hue-value to the 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 to the 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 text but less saturated. Note that this shadow is less expanded than the substrate (4px vs 7px):

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

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

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

Final result

Cream Cake

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 sample thinking what can I do on top of it… As in many other samples final results depends on both: the text itself (size, font and so on) and 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 (note 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 and intermediate shadow to light up 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 the most interesting step — actually I don’t need the full outlining (substrate) but only some it’s pieces. To hide excess details I will draw few shadows on top of the substrate (note that these shadows are less 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 to add some softening details.

Final result

Plastic

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 open for you some technics on how to use the transparency. Think on it: how would you use the text-shadow to draw something inside the text? Actually you can’t use the text-shadow to draw inner shadows. All the shadows you apply to the text are composed into a stack and are drawn one on top of another, and the text is drawn on top of all of them. So you need to make the text to 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. Note that 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

Painting

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 (I just have selected it to make visible):

color: transparent;

First of all let’s add a classic 3d-text effect (you can play here with the transparency). Note the increased lightness-value in the middle shadow — I found it to be 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 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 more transparent and with more lightness (to make this part more sharpen the most upper 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

Up & Down

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);

Internet Explorer and Windows 8

To try all these samples yourself and express your creativity with the text-shadow, don’t forget to get the latest platform preview of the Internet Explorer 10. All mentioned technics will also work with metro style apps for Windows 8 built using html and javascript. May The Shadow be with you! (But don’t use shadows just because you can.)

Note

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

Spread-distance value for text-shadows is currently defined in the ED for css4-text.

First letter

Our journey to the world of shadows continues. Last time we discussed the basics of using the box-shadow property. Today we are going to focus on the text-shadow.

Just to remind you: both properties meanwhile are defined in different modules actually work in a similar way. So if you are already familiar with the box-shadow you will easily understand the basics of the text-shadows art. Before we will jump to the practice lets deep a little bit into the theory to find out what is the difference between both .

text-shadow vs box-shadow

The first thing you need to know is that both specs (CSS3 Backgrounds and Borders and CSS3 Text) as for now (I’m writing this article in the mid. of February’12) are in the Working Draft status and thus they still may change. I will also discuss it while talking about the spread distance.

If you remember the syntax of the box-shadow it looks like that:

box-shadow: none | <shadow> [ , <shadow> ]*;
<shadow> = inset? && [ <length>{2,4} && <color>? ] 

The second rule in the full mode can be expanded as:

shadow = inset? h-offset v-offset blur-radius spread-distance color;

The spec for CSS3 Text describes the text-shadow property in a similar way:

text-shadow: none | [ <length>{2,3} && <color>? ]# 

Where:

Values are interpreted as for ‘box-shadow’.

So you may think on the full syntax for a one text-shadow effect as:

shadow = h-offset v-offset blur-radius color;

There are two differences here: first — you can’t create an inner shadow for the text, and second — there is no spread distance for text-shadow in CSS3 Text. Similar to the box-shadow you can create multiple shadows displayed on top of each other. Now lets have some practice.

text-shadow

Offsets and color

We will start from the very first steps — to define some horizontal and vertical offsets all that you need is to write up two length values (1.1–1.4):

Simple Shadow

Positive offsets move the shadow to the right and down (1.1):

text-shadow:10px 10px; width:300px;

Negative values define an offset moved to the left and up (1.2):

text-shadow:-5px -5px; width:300px; color:blue;

Next is the color. Lets first discuss what happens when the color is ommited. According to current version of the spec:

"If the color is absent, the used color is taken from the ‘color’ property."

If you will look across different browsers you may note that their behavior on that differs. Webkit-based browsers use transparent color in that case — and not because they are bad or they are doing something wrong. The point here is that the previous edition of the css3-backgrounds said:

omitted colors are a UA-chosen color.

I believe it will be fixed in future versions of Chrome, Safary and other webkit-browsers.

BTW ommiting the text-shadow color and thus applying to it the same color as the text has could be useful if you would like to create a blurred text effect (see samples 2.3 and 2.4 below).

To explicitly set the shadow’s color just add the color you want at the end of the rule:

text-shadow:-1px -1px white; color:blue; background:#333; /* 1.3 */
text-shadow:1px 1px rgba(255,255,255, 0.5); color:blue; background:#eee; /* 1.4 */

Note that while working with shadows you can use any color format defined in the CSS3 Color module including rgba() and hsla() functions with alpha-channel.

Blurring

The third length parameter is for the blur-radius (2.1–2.4):

Blurred Shadow

In accordance with the definition of the blur-radius for the box-shadow property you should use a nonnegative value (0 - for no blurring). Exact blurring algorithm can differ from one browser to another but in mathematical sense they all should be close enough to the Gaussian blur algorithm.

Text Shadow Blur Radius

In the first two samples (2.1 и 2.2) I’m using different blur-radiuses:

text-shadow:5px 5px 3px darkred; color:red; /* 2.1 */
text-shadow:4px -4px 10px red; color:azure;  background:#333; /* 2.2 */

In the second pair (2.3 и 2.4) I’m changing only the text and background color, and both shadows effects are applied using the same CSS-class 'blured-shadow':

.blured-shadow {
    text-shadow:0px 0px 4px ; /* the color is absent*/
}
color:red; /* 2.3 */
color:lightgray; background:#333; /* 2.4 */

Expansion and contraction

Now it is time to talk some more about web standards. I believe you should know it before you will try to use the spread value in the text-shadow in any of your projects. While working on the CSS3 Text module CSSWG decided to make a change to the previous version of this spec to allow a quicker progress towards the recommendation status. In this previous edition the text-shadow property included one more (fourth) length parameter — spread distance.

Similar to the box-shadow spread-distance for text-shadow allows to expand or contract the shadow.

As for now that definition of the text-shadow was moved to the L4 — and today you can find it in the ED for css4-text. Now I’m going to discuss how to use spread, you can try it in the latest versions of IE10 (as I know at the current moment IE is the only browser to support spread for text-shadows). Spread is a really power tool and allows to create some amazing samples! But it also may change in future. So be careful!

Spreaded Shadows

To increase the shadow set the spread-distance to a positive value (3.1):

text-shadow:5px 5px 0px 3px lightgreen; color:green;

To decrease — to a negative one (3.2):

text-shadow:8px 8px 2px -3px darkgreen; color:green; font-weight:900;

In case of zero-offet spread-distance can be used to outline the text (3.3):

text-shadow:0 0 0 3px rgba(128, 255, 0, 0.75); color:green;  background:#333;

And one more important note! Actually today the fourth length in the text-shadow rule is treated by not supporting browsers as a wrong text-shadow definition, and such rules are simply ignored. So if you would like to provide some level of compatibility for them you will need to double your text-shadows rules like that:

Spreaded Shadows

text-shadow: 0px 0px 10px lightgreen; /* 3.4 */
text-shadow: 0px 0px 10px 10px lightgreen; /* 3.5 */

Sometimes the shadow’s expansion could be emulated using multiple shadows with offsets in various directions (see samples 4.6 and 4.7 in the next chapter).

Multiple shadow

Finally and absolutely similar to the box-shadow you can apply multiple shadows to the text (4.1–4.5):

Multiple Shadows

Simple outlining (4.1):

text-shadow: 0 0 0 3px white, 0 0 0 4px gray; color:magenta;

Various blurred shadows with various offsets (4.2):

text-shadow: 3px 3px 4px 2px rgba(255,255,255,0.35), 
             6px -6px 4px 2px rgba(255,255,255,0.25), 
             -3px -3px 4px 6px rgba(255,0,255,0.15); 

Neon-effect (4.3):

text-shadow: 0 0 0 3px white, 
             0 0 2px 6px magenta,
             0 0 1px 9px white,
             0 0 6px 12px magenta;

And another neon-effect (4.4)

text-shadow: 0 0 2px #fff,
             0 0 4px 2px rgba(255,255,255,0.5),
             0 0 6px 6px #f0f,
             0 0 4px 7px #fff,
             0 0 3px 15px #222,
             -4px 0 2px 9px #f0f,
             4px 0 2px 9px #f0f,
             0 -4px 2px 9px #f0f,
             0 4px 2px 9px #f0f;

Text underlining (4.5):

text-shadow: 0 -3px 3px 15px white, 0 1px 2px 9px;
color:magenta;

Emulating expansion

Emulating Spreaded Shadows

As I already said technically you can use multiple shadows to create something similar to the real shadow expansion. So to emulate the sample (4.6):

text-shadow: 0px 0px 0px 4px magenta;

you can try to define multiple shadows with different offsets in various directions (4.7):

text-shadow: magenta 0px 2px, 
             magenta 2px 0px, 
             magenta -2px 0px, 
             magenta 0px-2px, 
             magenta -1.4px -1.4px, 
             magenta 1.4px 1.4px, 
             magenta 1.4px -1.4px, 
             magenta -1.4px 1.4px;

Actually there is some visual difference. Also you should understand that such technic has limited usage: it is less accurate and also negativelly affects the performance of the page rendering (the more rules you have the more comples is rendering).

More samples

Now as you already know all the basics of the text-shadows art lets try to build something more complex.

Classic rainbow (5.1):

Rainbow shadow

text-shadow: 0 0 2px 3px yellow,
             0 0 2px 6px orange,
             0 0 2px 9px red,
             0 0 2px 12px lime,
             0 0 2px 15px blue,
             0 0 2px 18px violet;

Double shadow (5.2):

Double arrow

text-shadow: 0 0 2px 2px white,
             2px 0 2px 5px #222,
             3px 0 3px 6px #933,
             5px 0 2px 14px #222,
             6px 0 5px 16px #533;

Flame-shadow (5.3):

Fire Shadow

text-shadow: 0 0 2px #eee,
             0 0 4px 2px #fff,
             0 -2px 4px 2px #ff3,
             2px -4px 6px 4px #fd3,
             -2px -6px 11px 6px #f80,
             2px -8px 18px 8px #f20;

Traditional “letter-press” effect (5.4):

Letter press

text-shadow: 0px 2px 3px #555;

Also traditional 3d-text (5.5):

3d text

text-shadow: 0 0 1px #999,
             1px 1px 1px #888,
             2px 2px 1px #777,
             3px 3px 1px #666,
             4px 4px 1px #555,
             5px 5px 1px #444;

Double shadow for a vintage-effect (5.6)

Vintage text

text-shadow: 2px 2px #fff,
             3px 3px #666;

Transparent text with contracted shadow (this effect also relies on the font size and typeface) - sample (5.7)

Light text

text-shadow: 0 0 2px -3px rgba(196,255,0,0.3),
             0 0 6px -5px #9c6;
color:transparent;

Using the text-shadow on the css pseudo-class ::first-letter (5.8)

First letter

.text {
    text-shadow:0 0 5px;
}
            
.text::first-letter {
    color:azure;
    text-shadow:0 0 5px, 0 0px 6px 3px blue, 0 -2px 6px 6px cyan, 0 -4px 9px 9px lightblue ;
}

Interactive sample

Hands-on: text-shadow

If you wish to play with shadows in an interactive way my colleagues created a cool demo for the Build conference in the last september: “Hands-on: text-shadow”.

Internet Explorer and Windows 8

The text-shadow rule is supported in IE10+ and you can use it in your metro style apps for Windows 8 (but one more time: think on metro design principles first, don’t apply special effects just because you can ;).

And just to remind you my previous recomendation on using filters: do not use them, or at least try to create you markup and styles in a such way that non-standard filters are not used for IE9+.

Note

CSS properties discussed in this article are defined in the CSS3 Text module which is currently in the Working Draft status. Meanwhile it seems to be quite stable it still can change in details.

Today we will start studing the art of mastering shadows with the new CSS3 modules. We are going to look in details at two properties: box-shadow и text-shadow, defined respectively in the modules CSS3 Backgrounds and Borders and CSS3 Text.

Both properties work in a similar manner but with some exclusions.

The first part is totally about how to create box shadows and the second one moves the focus to the text continuing with the third one digging into 7 really cool samples. (So stay tuned!)

box-shadow

First of all there is one thing you should remember: the shadow does not increase or decrease the size of the box or its border. The spec says:

shadows do not trigger scrolling or increase the size of the scrollable area.

Offset and color

Simple Shadow

To create the most basic shadow all that you need is to define the first two parameters of the rule: horizontal and vertical offset of the shadow (1.1):

box-shadow: 3px 3px;

A positive value moves the shadow to the right and down, and a negative one to the left and up.

By default if you did’t specify the shadow’s color most of the popular browsers will use the text color in current context (1.2). (The spec changed in February’12, in previous edition ommited box-shadow “colors were UA-chosen colors”. So you may find some browsers with a different behaviour.):

box-shadow: 3px 3px; color:blue;

To set the color of the shadow all that you need is just to add a color value at the end (1.3):

box-shadow: 3px 3px darkgreen;

To define the color you can use any of available in CSS3 notations: #RGB, #RRGGBB, namely, by rgb() or rgba() and hsla() functions with alpha-channel. hsla-function is very useful while building complex samples.

Blurring

Blurred Shadow

The third one length you can set is a blur radius — a positive value defining how much the shadow’s edge is blurred (2.1–2.3):

box-shadow:3px 3px 3px darkgrey;

By default the blur-radius equals zero and the shadow’s edge is sharp.

By combining blurring with the shadow’s offsets you can achive various effects. On the sample (2.3) both offets are equal to zero, but thanks to the blurring effect there is a shadow around the box:

box-shadow:0 0 9px black;

The blurring algorithm is not defined by the spec itself, but it says that the blurring effect should approximate the Gaussian blur with with a standard deviation equal to half of the blur radius. In other words it means that the actual shadow generated by different UAs can differ at some pixels.

Gaussian blur

Spreading

Spreaded Shadow

The fourth length is for spread-distance to expand or contract the shadow. By default the shadows’s size equals to the box’s one, but using the spread you can change it. Also I should note here that this parameter was introduced in later spec versions, so many out of date tutorials and samples you will find in the wild web have no idea on its existence. ;)

To expand the shadow set a positive spread-distance (3.1, 3.2):

box-shadow:6px 6px 0px 4px darkred;

To contract — use a negative one (3.3):

box-shadow:12px 12px 8px -4px darkred;

Defining spread value you can think on it as a shadow scaling operation, but actual algorithm if defined by the spec in a little bit more complex way using blurring analogy and deleting transparent or opaque pixels.

Spreaded Shadow

On the sample above (3.4) the shadow has horizontal and vertical offsets of 6px to the left and down and is expanded for 8px from each side:

box-shadow:6px 6px 0 8px grey;

If you use rounded corners on you box expect that the border-radius of the expanded shadow will be alse scaled up (3.5):

Spreaded Shadow with border-radius

Inner shadow

Inner Shadow

Finally one more interesting modificator you can define is the “inset" keyword which allows you to draw an inner shadow in your box (4.1-4.4):

box-shadow:inset 4px 4px rgba(66,66,66,0.5); /* (4.1) */
box-shadow:inset 4px 4px 0 8px rgba(198,198,198,1); /* (4.2) */
box-shadow:inset -2px -2px 8px 0px black; /* (4.3) */
box-shadow:inset 0 0 4px 0px black; /* (4.4) */

Note that the inner shadow is drawn only inside the box. And if you use positive (expanding) spread-distance on inner shadow it means contracting the shadow’s perimeter shape (4.2).

Multiple shadows

And the last one piece of the mosaic: you can define as much shadows for the same box as you want by writing all of them comma-saparated in the same rule.

For example to create a rainbow shadow (5.1) all you need to do is to write up 7 shadows with increasing spread-distance:

box-shadow: 0 0 2px 1px red,
            0 0 2px 2px orange,
            0 0 2px 3px yellow,
            0 0 2px 4px green,
            0 0 2px 5px lightblue,
            0 0 2px 6px blue,
            0 0 2px 7px violet;

Rainbow Shadows

Note that the shadow effects are applied front-to-back. The violet shadow one will be drawn first, on top of it will be drawn the blue one and so on… the red one will be drawn at the end on top of other shadows, and finally — the box it self with all its content.

As all the shadows are independed you can easily combine shadows with different offsets (5.2):

box-shadow: -6px -6px 8px -4px rgba(255,0,0,0.75),
            6px -6px 8px -4px rgba(0,255,0,0.75),
            6px 6px 8px -4px rgba(255,255,0,0.75),
            -6px 6px 8px -4px rgba(0,0,255,0.75);

Colorful Shadows

Or combine outter and inner shadows (5.3):

box-shadow: inset 0 0 8px lightgray,
            1px 1px 3px darkgray;

Inner Shadows

Here is an underline (or a bottom shadow) sample (5.4):

box-shadow: 0 1px red,
            0 3px 3px -2px black

Underline Shadows

By adding some special effects on the :before and :after prseudo-classes with content you can create a slick-box described by Matt Hamm (5.5):

.slick-box {
    position: relative;
    height: 50px;
    border: 1px solid #efefef;
    background: #fff;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.06) inset;
}

.slick-box:before, .slick-box:after {
    content: '';
    z-index: -1;
    position: absolute;
    left: 10px;
    bottom: 10px;
    width: 70%;
    max-width: 300px; /* avoid rotation causing ugly appearance at large container widths */
    height: 55%;
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
    transform: skew(-15deg) rotate(-6deg);                 
}
            
.slick-box:after {
    left: auto;
    right: 10px;
    transform: skew(15deg) rotate(6deg);                 
}

Slick Shadows

(To simplify the code I removed all the vendor prefixes, but while trying to reproduce it you should use all these -ms-transform, -webkit-transform and so on.)

Common syntax

Summing up the common syntax for box-shadow looks like this:

box-shadow: <shadow> [ , <shadow> ]*;
<shadow> = inset? && [ <length>{2,4} && <color>? ] 

The last one rule in a full version means:

box-shadow: inset? h-offset v-offset blur-radius spread-distance color;

The blur-radius and the spread-distance can be ommited. The inset keyword switched the shadow form outter to inner.

Interactive sample

Hands-on: box-shadow

If you wish to play with shadows in an interactive way my colleagues created a cool demo for the Build conference in the last september: “Hands-on: box-shadow”.

Internet Exlorer and Windows 8

Yeah! Here it is: box-shadow is supported in IE starting with IE9 (and with hardware acceleration!). You can also use it in your metro style apps for Windows 8 built with html/js (but remember about metro design principles and don’t apply special effects just because you can ;).

And the last one thing I need to say: please, please, please do not use non-standard filters and do not combine old filters with new CSS3 rules.

Note

CSS properties discussed in this article are defined in the CSS3 Backgrounds and Borders module which is currently in the Working Draft status. Meanwhile it seems to be quite stable it still can change in details.