Gestion des sprites CSS avec Sass

Gestion des sprites CSS avec Sass (le 24 octobre 2013)

Sur le projet sur lequel je travaille actuellement, j'ai dû me coltiner la gestion de sprites CSS optimisés pour des écrans Retina, et surtout en grand nombre et dans plusieurs formats différents (genre 80 icônes avec leur version survolée et encore un troisième état, que nous appellerons « actif »).

Autant le dire, cet aspect du projet est plutôt rébarbatif, et les fonctions « magiques » de Sass de gestion des sprites m'ont vite montré leurs limites (ou les limites de mes connaissances en Sass se sont vite montrées me dira un expert en Sass :) ). En tout cas, cela ne convenait pas à mon cas.

Finalement, pour des icônes toutes semblables de ce genre (j'ai juste ajouté un fond au lieu de la transparence) :

Grilles d'icônes en sprites CSS

Voici l'approche que j'ai prise : d'abord une classe générale qui contient toutes les propriétés communes qui permettra de factoriser et ensuite chaque classe de chaque icône qui décale l'image de fond pour afficher la bonne image. Chaque icône dans ce sprite fait 48 pixels de large, pour un affichage de 24 pixels donc (optimisé Retina). Les icônes sont côte à côte par rangs de 10.

Seulement, gérer cela à la main avec 6 icônes, pas de souci, mais pour plus de 80 icônes, c'est hors de question.

Bref, j'ai bricolé une fonction Sass qui ressemble à cela :

// ici les propriétés générales 
.icon-service-general {
background-image: url('../../layout/images/icon-services-48.png');
background-repeat: no-repeat;
display: inline-block;
width: 24px;
height: 24px;
background-size: 240px 576px;
/* la moitié des dimensions de l'image du sprite : optimisation retina */
}


$x: 0;
$y: 0;
$grid: 24px;


// là je limite la liste pour l'exemple
@each $service in performance, motion, presentations, etc. {
// on factorise avec la classe « général »
.icon-service-#{$service} {
@extend .icon-service-general;
}


// je décale de tant de fois la grille
.icon-service-#{$service} {
background-position: ( -( $x * $grid ) ) ( -( $y * $grid ) );
}
// idem pour le rollover
a:hover .icon-service-#{$service},
a:active .icon-service-#{$service},
a:focus .icon-service-#{$service} {
background-position: ( - ($x * $grid) ) ( -( $y + 1) * $grid );
}


$x: $x+1;


@if $x == 10 {
// la taille de la grille = 10 icônes côte à côte
$x: 0;
$y: $y+3; // de 3 (fois la grille) en 3
}
// etc .
}

Ce qui va générer la CSS suivante :

// ici les propriétés générales 
.icon-service-general, .icon-service-performance, etc. {
// ici les propriétés communes
}


.icon-service-performance {
background-position: 0px 0px;
}
a:hover .icon-service-performance,
a:active .icon-service-performance,
a:focus .icon-service-performance {
background-position: 0px -24px;
}


/* etc. */

Le gros avantage, c'est que c'est facilement adaptable à une grille d'icônes de n'importe quelle largeur, Retina ou non. Et surtout, ça fait le sale boulot tout seul.

Bref, bien travailler pour moins travailler.

5 commentaires

Posté par Pascal (eQRoeil) le 24/10/2013 à 18:00:02
Salut Nico,

en passant je te reparle de grunticon, il faudra bien que tu testes un jour ; )

Avec des icones en svg un drag & drop de tes icones sur grumpicon.com tu aurais obtenu les fichiers css qui vont bien :

- un pour les navigateurs qui supportent svg
- un pour navigateurs qui supportent png en base64
- un pour navigateurs qui ne supportent ni l'un ni l'autre, avec les icones en png

un petit script js qui détecte le support de svg (et base64) et fournit le bon fichier css.

Avantages :

- pas de boulot côté css ou prépro
- pour svg (et png base64) une seule requête comme la sprite
- requête non bloquante
- un bien meilleur support que les icon font (autre solution possible mais tu laisses du monde sur le carreau)
- svg et retina font bon ménage

Have a look ; )

Posté par Pascal (eQRoeil) le 24/10/2013 à 18:03:35
J'oubliais une question :

Tu n'as pas eu de souci avec background-size sur certains (vieux) navigateurs ?

Posté par Nico le 25/10/2013 à 8:56:38
Oui, ça fait partie de mon immense to-do et to-read list (sourire)

J'avais bien envisagé de passer par SVG (j'ai utilisé ça pour le logo), toutefois, le trop grand nombre d'icônes m'a fait choisir les sprites CSS.

Pour le background size, j'ai utilisé un polyfill pour IE8, et le 7, je le patcherai si vraiment il le faut (sourire)
Posté par Pascal (eQRoeil) le 26/10/2013 à 22:55:17
Salut Nico,


c'est ce polyfill que tu as utilisé ?

https://github.com/louisremi/background-size-polyfill
Posté par Nico le 26/10/2013 à 23:02:20
Effectivement, c'est bien celui-là que j'ai utilisé. (sourire)

Ajouter un commentaire









L'option « Se souvenir de mes informations » utilise un cookie, elle ne sera pas effective si vous les avez désactivés.

Les balises HTML ne seront pas interprétées, il est donc inutile d'en mettre. Par contre, les sauts de lignes de votre commentaire seront pris en compte, ne mettez donc pas de <br />, le site s'en chargera. Bien sûr, un commentaire vide ne sera pas ajouté !

L'auteur (autrement dit moi) n'est pas responsable des éventuelles fautes d'orthographe dans les commentaires.
Tout propos raciste et/ou insultant sera supprimé sans préavis. Les commentaires hors de propos destinés à faire de la pub pour des sites seront également supprimés sans ménagement.

Je vous prie de me pardonner, j'ai énormément de mal à lire le "langage" SMS, il n'est donc pas du tout interdit de s'abstenir de l'utiliser. Qui plus est, vous avez sûrement un clavier digne de ce nom et pas celui d'un téléphone portable. Ne vous gênez pas pour utiliser l'option "Prévisualiser" si vous voulez vous relire avant de poster, je vous en remercie d'avance !

Cet article a été écrit par Nicolas Hoffmann.

Ce site est la propriété de Nicolas Hoffmann.
Tous droits réservés, les textes du blog sont publiés sous licence CC BY-NC-SA.