CSS3 c’est pour l’aspect vendeur du nom, car au final on va aussi et surtout bénéficier du service de pseudo éléments (:after et :before) qui sont prévus depuis CSS2.1.
Les visuels que vous voyez sur la page de démonstration ne sont composés qu’avec des propriétés CSS sur une seule et unique <div> (pour chaque bloc).

Chez moi le meilleur rendu est sous Firefox, notamment pour la dernière ombre qui est un peu osée (au passage il semblerait que la propriété opacity ne fonctionne pas sur les pseudo-éléments).

Dans cette démonstration nous allons utiliser des propriétés avancées de CSS2.1 (:before et :after) qui sont des pseudo-éléments.
Des pseudo-éléments permettent de construire un élément dans la structure de votre document (DOM) sans vraiment en construire un… ok, ça commence bien pour l’explication.

Pseudo-éléments :after et :before

Imaginez que dans un site vous souhaitiez ajouter derrière un lien la langue du site en référence (qui, pour rappel, se précise grâce à l’attribut hreflang sur un élément <a>) vous pouvez le faire en passant par du CSS :

a[hreflang]:after {
	content : " ("attr(hreflang)")";
}

Ainsi tous les liens porteurs de l’attribut hreflang se verront agrémentés d’un « (en) », dans le cas d’un lien anglais par exemple :
Mon lien (en)

La base de travail

Sur le même principe nous allons pouvoir construire deux pseudo-éléments qui vont nous servir à composer les différentes ombres que vous pouvez visualiser sur la démonstration.

Pour résumer simplement notre démarche nous avons des divisions :

<div class="bloc">Without drop shadow</div>

qui portent toutes la classe bloc, cette classe nous sert de base pour les styles des blocs de démonstration (ça ressemble vaguement à une feuille… du moins j’espère).
La classe without, dans le premier exemple de la page de démonstration, me sert juste à définir le bloc qui n’a pas d’ombrage, mais passons.

Voici le CSS correspondant, les principales propriétés à retenir sont celles de positionnement et de dimensions à fixer, mais je vous donne tout de même la totalité :

.bloc {
	position: relative;
	display: inline-block;
	vertical-align: top;
	margin: 35px 26px;
	padding: 25px;
	width: 220px;
	height: 110px;
	background: #f0e8d8;
	font-size: 1.6em;
	line-height: 5em;
	font-family: Georgia, Times, Serif;
	text-align: center;
	background-image: linear-gradient(to bottom, #dacdb1 11%, #f0e8d8 56%);
	box-shadow: 0 0 65px #cdbe9f inset, 0 0 20px #beae8c inset;
}

Ensuite nous allons construire nos pseudo-éléments de manière globale :

.bloc:after, .bloc:before {
	content: " ";
	position: absolute;
	width: 50%;
	height: 100px;
	z-index: -10;
}

.bloc:before { background: green;}
.bloc:after { background: red; }

Les pseudo-blocs ont une position absolue et un z-index négatif, le but étant de placer ces éléments sous leur parent (la <div> dont ils dépendent).

Les couleurs sont là pour faire du repérage dans le positionnement des pseudo-éléments.
À ce propos j’avais prévu de vous inviter à utiliser Firebug pour jouer avec le fond des .bloc, mais grâce à une suggestion de Felipe, je vous ai développé un petit joujou pour visualiser les pseudo-éléments sans vous demander trop d’effort :p

Bref, revenons-en à nos moutons.

Les pseudo-blocs sont prêts, il ne nous reste plus qu’à leur offrir une ombre portée ainsi qu’un positionnement précis.
Dans certains cas nous aurons besoin d’autres petites choses, mais nous verrons cela au fur et à mesure.

Tous les codes CSS suivants vont s’appliquer à un élément porteur de la classe bloc combiné à la classe dont fait référence le code CSS.
Exemple, pour le prochain effet, nous aurons besoin d’un élément de cette forme :

<div class="bloc simple">Soft Drop Shadow</div>

À noter, certaines propriétés CSS3 doivent être préfixées (-webkit-, -moz-, etc.), cela dépend du support navigateurs souhaité et de votre projet.

Ombre simple

Il n’est jamais de trop de rappeler certaines bases, notamment sur l’utilisation de la propriété box-shadow.

.simple {
	box-shadow: 0 0 65px #cdbe9f inset, 0 0 20px #beae8c inset, 0 0 5px #816f47;
}
.simple:after, .simple:before { display: none; }

Ici nous n’avons pas besoin des pseudo-éléments, nous les cachons.
Ici il s’agit du même code que pour les ombres de notre base, sauf que nous ajoutons une ombre portée.

box-shadow permet d’attribuer plusieurs ombres à un élément. La syntaxe de base :

box-shadow: 1px 2px 9px 0 #000;

permet la création d’une ombre portée dont voici les paramètres, dans l’ordre d’apparition :
1px de décalage horizontal (vers la droite), 2px de décalage vertical (vers le bas), 9px  de diffusion et 0 d’étendue (complètement optionnel), #000 de couleur.
Un paramètre optionnel, inset, placé après la couleur, permet d’indiquer que l’ombre portée est en fait une ombre interne à l’élément. Sans ce paramètre, l’ombre est considérée comme portée.

La multiplication de cet ensemble d’informations séparé par une virgule permet la création d’ombres multiples.

Les ombres latérales

C’est ici que l’on va découvrir l’intérêt des pseudo-éléments.

Ici nous allons positionner un des pseudo-blocs et lui donner une largeur et une hauteur, ainsi qu’une ombre portée.

.laterals:before {
	top: 15px;
	left: 0;
	width: 100%;
	height: 130px;
	
	border-radius: 12px / 65px;
	box-shadow: 0 0 10px #555;
}
.laterals:after { display: none; }

Le border-radius nous permet d’avoir un effet légèrement gondolé sur l’ombre, ce qui ajoute un poil de réalisme.
N’oubliez pas de profiter de la fonction X-Ray pour visualiser le pseudo-élément et son comportement.

Ombre latérale courbe

Simple mais pas trop, simple dans le sens où il n’y en a que d’un côté.
Encore une fois nous n’allons utiliser qu’un des deux pseudo-éléments.

Ici nous allons utiliser une rotation pour donner cet effet.

.lateral:before {
	top: 10px;
	left: 8px;
	width: 50%;
	height: 130px;
	
	box-shadow: -7px 0 10px #555;
	transform: rotate(-5deg);
}
.lateral:after { display: none; }

Vous pouvez voir le petit décalage négatif de l’ombre, le but étant de le diriger vers la gauche.

Ombres horizontales

C’est un peu le même principe que précédemment, sauf que, partant du principe qu’on peut très bien ne pas connaître la hauteur d’un bloc, j’utilise cette fois les deux pseudo-éléments pour produire cet effets.

Nos deux pseudo-éléments sont donc positionnés l’un par rapport au haut du bloc parent (la <div> dont il dépend), l’autre par rapport au bas.

.horizontal:before {
	top: 0px;
	left: 5%;
	width: 90%;
	height: 50px;
	
	border-radius: 125px / 12px;
	box-shadow: 0 0 8px #555;
}
.horizontal:after { 
	bottom: 0px;
	left: 5%;
	width: 90%;
	height: 50px;
	
	border-radius: 125px / 12px;
	box-shadow: 0 0 8px #565656;
}

J’ai un peu dupliqué les styles pour que ce soit bien clair, mais vous pouvez bien entendu réunir les styles communs dans une seule déclaration.

Ombre horizontale simple

C’est l’étape la plus complexe de cet article je pense.

En ajoutant la classe single à notre élément :

<div class="bloc horizontal single">Single Horizontal</div>

et en appliquant, en plus des précédents, ce code CSS :

.single:before { display: none; }

Le tour est joué 😉
Autre solution, plutôt que de créer les deux ombres pour en cacher une, il vous est simplement possible de n’en créer qu’une… Évident, mais je préfère le souligner.

Ombres courbés

C’est certainement l’effet le plus en vogue chez les webdesigners qui souhaitent apporter une touche de profondeur à leur design.

Pour réaliser cet effet nous allons devoir utiliser nos deux pseudo-éléments.

.curve:before {
	top: 52px;
	left: 5px;

	transform: rotate(-5deg);
	box-shadow: 7px 6px 15px #333;
}
.curve:after {
	top: 52px;
	right: 5px;
	
	transform: rotate(5deg);
	box-shadow: -7px 6px 15px #333;
}

Trop facile !

Toujours sur le même principe, il vous suffira d’ajouter la classe single stylée plus haut pour faire disparaitre l’ombre d’un des deux côtés. De quoi simplifier bien largement vos intégrations !

Ombre expérimentale

Alors celle-ci… ne regardez pas sous Chrome !
Vous ne verrez rien non plus avec le X-Ray pour la simple et bonne raison que j’utilise l’intégralité des pseudo-éléments (et pas uniquement leur box-shadow), pour produire cet effet, encore expérimental.

Le code CSS correspondant est plutôt lourd en terme d’ombre portée… et plutôt difficile à paramétrer :

.drop:before {
	left: -5px;
	top: 167px;
	width: 280px;
	height: 4px;
	background: #aaa;

	border-radius: 140px / 2px;
	box-shadow: 0 0 5px #aaa, 0 0 10px #888, 0 0 15px #666;
}

.drop:after {
	left: 8px;
	top: 168px;
	width: 255px;
	height: 2px;
	background: #666;
	
	border-radius: 125px / 1px;
	box-shadow: 0 0 5px #444, 0 0 8px #333, 0 0 10px #666;
}

Le pseudo-élément :before me sert d’ombre large, les drop-shadow y sont donc plutôt complexes.
Le pseudo-élément :after me sert d’ombre fine, au centre de l’ombre large, les drop-shadow sont donc légèrement plus simples.
Dans les deux cas nous les transformons dans un premier temps en ellipse.

Bogues

S’il vous arrivait de ne pas voir apparaitre les ombres, vous êtes peut-être dans le cas rencontré par les lecteurs et commentateurs du blog :
Les blocs ombrés sont des enfants d’au moins un autre bloc (un « container » quoi). Si ce bloc possède une couleur de fond, les ombres vont disparaitre derrière le bloc.
C’est une histoire de z-index à réordonner.
Dans notre exemple, il suffit de positionner votre élément (en absolute ou relative) et de lui attribuer un z-index de 0, exemple :

.container {
   position:relative;
   z-index: 0;
}

Merci à Ivan d’avoir fourni un exemple de code concret.

Le mot de la fin

J’espère que vous n’aurez pas eu trop de difficulté à suivre ce tutoriel dont les explications restent relativement sommaires.
La fonction X-Ray devrait vous servir à trouver certaines réponses à vos questions, mais pour les autres n’hésitez pas à me consulter via le système de commentaire de ce blog.

J’ai bien conscience que le sujet a déjà été abordé ici : Nimbupani et là : NicolasGallagher. Mais cet article est en rédaction depuis début décembre, et il apporte ma vision des choses, je me suis donc décidé à le terminer :)

Merci pour votre lecture !

Cet article est également disponible en : Anglais