La technique nous vient des vieux jeu vidéos. À l’époque, on disposait toutes les images bitmap dites « sprites » du jeu dans un seul fichier. Aujourd’hui, l’idée est récupérée par le CSS qui permet de rassembler des images, idéalement de petites dimensions en une seule image. Essentiellement pour limiter le nombre de requêtes au serveur. C’est une pratique fortement conseillée et d’ailleurs exigée par de nombreux tests comme Google PageSpeed Insights ou GTmetrix. Ce dernier permet d’ailleurs une bonne compression des images.
On aurait pu croire que cela augmente le poids des images. Les 250 couleurs d’un petit pictogramme de 32 pixels deviennent celles d’une grande image de 200 pixels. Et d’ailleurs il n’est pas question de mettre toutes vos photos dans une seule image, mais bien des pictogrammes et des éléments visuels d’un même site. À la limite le logo d’un site web, bien que pour ce dernier je préfère de loin l’image vectorielle.
Je n’ai pas vraiment exploité cette fonctionnalité au début du CSS. Les images étant déjà indexées et fortement optimisées en quelques couleurs. Depuis cette technique s’avère fort utile considérant le nombre grandissant de requêtes, à différents serveurs, la grandeur des images, leur poids, la haute résolution versus les petits appareils comme les mobiles. Une petite classe CSS peut redéfinir toutes vos image du site selon la résolution Retina, ultra HD, etc.
Pour un développeur c’est avantageux de pouvoir utiliser un CSS de base avec une seule image à copier à chaque nouveau site. Pour ma part, j’ai converti les pictogrammes de la nouvelle version de mon gestionnaire de contenu en sprites. Vous allez me dire que j’aurais dû en profiter pour mettre à niveau mes images. Mais c’est ce qui a de merveilleux avec les sprites, il suffit de modifier une seule image pour mettre à jour l’ensemble des images du site. Ça viendra ; -)
C’est par ailleurs facile à utiliser. Une fois créés, nos sprites s’affichent comme une simple balise. Le défaut, aucun changement dynamique de couleur ou des dimensions comme le SVG ou le jeu de police de caractères. C’est pourquoi il nous faut trois images. Par exemple une image normale, une seconde pour l’effet réactif (rollover) et une troisième pour l’état inactif. Mais une fois les images amalgamées, une fois l’image sur le serveur, le CSS peut faire des merveilles.
- Les pseudo-sélecteurs CSS permettent de changer dynamiquement de classe.
- Alors qu’un simple recadrage (changement de position) suffit pour changer d’image!
L’idéale est de penser ses sprites par groupe. Personnellement j’ai un sprite pour mes images de marque et un autre pour les éléments de navigations, que je copie de site en site. Et enfin un par site, avec les éléments graphiques, logos et pictogrammes spécifiques au site. Ensuite, j’essaie de faire des images de mêmes couleurs, ce qui aide déjà l’ergonomie. Mais surtout avec les mêmes dimensions ou proportionnelle. Les plus alignées possible. Il n’est pas rare de voir des pictogrammes alignés. De cette façon le calcul est beaucoup plus facile. Les images ont toute 21x21 pixels : 0, 21, 42, 63, 84, 105, 126, 147...
Le code CSS
L’image :
Un élément HTML, n’importe lequel en « bloc en-ligne » display:inline-block;
auquel on ajouter une image de fond. J’utilise deux classes pour ce faire. Une première classe de base pour tous les sprites :
.cSprites{
display:inline-block;
vertical-align:middle;
background:url(images/neural_extra-spirits.png) no-repeat;
}
Et une deuxième par sprite avec ses dimensions width
et height
et sa position dans l’image background-position
:
.cSpriteAjout { width: 21px; height: 21px; background-position: 0px 0px; }
Et la balise en question, ici l’exemple avec deux balises « italique » et « span » :
<i class="cSprites cSpriteAjout"></i> <!-- ou --> <span class="cSprites cSpriteAjout"></span>
Le CSS affiche seulement un espace de 21px par 21px de l’image de fond, recadré à partir de la position de fond. La première image est toujours à 0,0, c’est-à-dire la position X/Y du coin supérieur droit :
La deuxième, la position d’origine zéro moins (-) la largeur des images précédentes, -21px dans cet exemple (réactif) :
Et ainsi de suite, -42 pixels dans le troisième bouton (inactif) :
Même chose pour les lignes suivantes :
Exemple avec un « rollover »
Pictogramme et boutons avec curseur | sans curseur avec alignement vertical...
Dans cet exemple, une classe:hover
change seulement le position :
.ajout_n:hover { background-position:-21px 0px; }
<style> /* Premier bouton, en haut à gauche (0,0) */ .ajout_n{ vertical-align:middle; cursor:pointer; display:inline-block; background:url(images/neural_extra-spirits.png) no-repeat; width:21px; height:21px; background-position:0px 0px; } /* Deuxième bouton, état réactif (hover) */ /* Puisque c’est la même classe, il */ /* suffit d’un repositionnement */ .ajout_n:hover { background-position:-21px 0px; } /* Troisième bouton, inactif */ /* sans courseur... */ .ajout_b{ vertical-align:middle; display:inline-block; background:url(images/neural_extra-spirits.png) no-repeat; width:21px; height:21px; background-position:-42px 0px; } /* Deuxième image, deuxième ligne */ .importation_n{ vertical-align:middle; cursor:pointer; display:inline-block; background:url(http://neural3.com/extra/images/neural_extra-spirits.png) no-repeat; width:21px; height:21px; background-position:0px -21px; } .importation_n:hover { background-position:-21px -21px; } .importation_b{ vertical-align:middle; display:inline-block; background:url(images/neural_extra-spirits.png) no-repeat; width:21px; height:21px; background-position:-42px -21px; } </style> <i class="ajout_n"></i> <i class="importation_n"></i> | <i class="ajout_b"></i> <i class="importation_b"></i>
Puisque la dimension de l’objet peut être modifiée en ligne (in-line) il peut arriver que l’image soit effectivement bien cadrée, mais avec les mauvaises dimensions. Il s’agit d’un simple width et height en fin de compte. Dans ce cas, les autres sprites deviennent visibles avec un résultat plus que décevant. Pour ma part je m’assure d’éviter cette situation. Mais Aaron Barker propose Diagonal CSS Sprites. La diagonale, en plaçant les images en diagonale aucune image ne peut se retrouver dans le cadre d’une autre image, avec toute fois un vide sidéral!
Le pseudo-élément :before
pour la liste à puce.
Un autre méthode est particulièrement bien adaptée pour les listes à puce avec un alignement à gauche :
- Ajouter un texte
- Exporter un texte
<style> .ajout_b:before { content: ""; width: 21px; height: 21px; background: url(/documents/images/2016/neural_extra-spirits.png) 0 0 no-repeat; float: left; margin-right: 10px; } .importe_b:before { content: ""; width: 21px; height: 21px; background: url(/documents/images/2016/neural_extra-spirits.png) 0 -21px no-repeat; float: left; margin-right: 10px; } .ajout_b, importe_b {list-style-type:none;} </style> <ul> <li class="ajout_b"> Ajouter un texte</li> <li class="importe_b"> Exporter un texte</li> </ul>
Conclusion
Le sprite est une excellente alternative à défaut d’avoir des images SVG ou d’utiliser une police de caractère plus difficile à créer.
Références
- CSS Sprites: Image Slicing’s Kiss of Death par Dave Shea
- Sprites CSS : Meurs, découpe d’images, meurs ! traduction par Steve Frécinaux
- Les sprites CSS par Nicolas Hoffmann
- SpriteMe makes spriting easy par Steve Souders
- Diagonal CSS Sprites pas Aaron Barker
- CSS Sprite Generator
- Stitches An HTML5 sprite sheet generator
- CSS Sprite Generator
- Google PageSpeed Insights
- GTmetrix