Bon, à la base, j'ai voulu utiliser la technique décrite dans l'article Onion Skinned Drop Shadows sur A List Apart. Je l'ai un peu modifiée pour pouvoir utiliser des PNGs avec de la transparence alpha; seul le coin en bas à droite est encore un PNG sans transparence. Enfin c'est pas ça l'important.

L'important, c'est que la technique proposée a un inconvénient : elle nécessite d'ajouter des DIVs non sémantiques. Et ça, c'est Mal :-)

On va donc utiliser un peu de Javascript pour les ajouter, pour éviter d'avoir un code tout sale !

ombrage.js

function insertShadowDiv (elt, className) {
	if (elt.hasAttribute('id')) {
		var id = elt.getAttribute('id') + "_ext";
	}
	var classext = className + '_ext';
	var classmid = className + '_mid';
	var classint = className + '_int';
	var parent = elt.parentNode;

	var extdiv = document.createElement('div');
	extdiv.setAttribute('class', classext);
	if (id) {
		extdiv.setAttribute('id', id);
	}

	var middiv = document.createElement('div');
	middiv.setAttribute('class', classmid);

	var intdiv = document.createElement('div');
	intdiv.setAttribute('class', classint);

	middiv.appendChild(intdiv);
	extdiv.appendChild(middiv);

	parent.replaceChild(extdiv, elt);
	intdiv.appendChild(elt);
}

function createShadows(className) {
	var elements = document.getElementsByClassName(className);
	for (var i = 0; i < elements.length ; i++) {
		insertShadowDiv(elements[i], className);
	}
}

/* tiré de
 * http://daniel.glazman.free.fr/weblog/newarchive/2003_06_01_glazblogarc.html#s95320189
 */
document.getElementsByClassName = function (needle)
{
  function _GetElementsByClass(outArray, seed, needle)
  {
    while (seed) {
      if (seed.nodeType == Node.ELEMENT_NODE) {
        if (seed.hasAttribute("class")) {
          var c = " " + seed.className + " ";
          if (c.indexOf(" " + needle + " ") != -1)
            outArray.push(seed);
        }
        _GetElementsByClass(outArray, seed.firstChild, needle)
      }
      seed = seed.nextSibling;
    }
  }

  var outArray = new Array();
  _GetElementsByClass(outArray, document.documentElement, needle);
  return outArray;
}

Fichier HTML utilisant ce code

Dans le fichier suivant, on peut remplacer present_ombre par ce qu'on veut, à condition de le remplacer aux deux endroits. Ici, tous les éléments de cette classe se verront rajouter les div imbriqués par le code Javascript.

<html>
 <head>
  ...
  <script type='text/javascript' src='js/ombrage.js'></script>
  ...
 </head>
 <body onload='createShadows("present_ombre"); return true'>
  ...
  <div class='present_ombre' id='friends_rss'>
   ...
  </div>
  ...
 </body>
</html>

Fichier de style CSS associé

On voit que le code JavaScript a utilisé des noms de classes dérivant du nom de la classe initiale. C'est ici l'exemple utilisé sur la page d'accueil. Par ailleurs, si l'élement de la classe initiale avait un id, le DIV le plus extérieur prendra également un id, du type id_ext (par exemple, dans l'exemple ci-dessus: friends_rss_ext). En effet, certains styles nécessitent d'être appliqués sur le DIV extérieur, par exemple le style float, alors que d'autres doivent être appliqués sur le bloc intérieur.

.present_ombre_ext {
	background-image: url(../images/ombrage/shadow_right.png);
	background-repeat: no-repeat;
	background-position: 100% -12px;
}

.present_ombre_mid {
	background-image: url(../images/ombrage/shadow_bottom.png); 
	background-repeat: no-repeat;
	background-position: -12px 100%;
}

.present_ombre_int {
	background-image: url(../images/ombrage/shadow_br.png);
	background-repeat: no-repeat;
	background-position: bottom right;
	padding-right: 9px;
	padding-bottom: 9px;
}

CSS pour Internet Explorer Windows

En fait, pour Internet Explorer Windows, on supprime les images de fond, car il ne sait pas appliquer correctement les PNGs avec transparence non binaire. C'est l'effet des trois premières directives.

Par ailleurs, il semble qu'il ne sait pas non plus gérer correctement le bout de code Javascript, donc en fait, les DIVs supplémentaires ne sont pas insérés... Donc on doit penser à appliquer aussi les styles du bloc extérieur sur l'id du bloc intérieur.

/* hack IE sauf IE Mac */
/* \*/
* html .present_ombre_ext {
	background-image: none;
}

* html .present_ombre_mid {
	background-image: none;
}

* html .present_ombre_int {
	background-image: none;
	position: relative; /* pour forcer le reflow ... */
}
 
* html #friends_rss {
	styles de #friends_rss_ext
}
/* */