Kortic, Anthony Ladeuil

Encodage SVG pour CSS

L'intégration de pictogrammes et autres logos dans un site web s'effectue de différentes manières : svg inline, img src="path/to/image", etc… Pour l'intégration via CSS nous pouvons le faire également en encodant en base64 le contenu du SVG au détriment d'un surpoids d'environ 30%.
Une alternative CSS consiste à encoder le contenu XML du SVG de telle sorte que l'on puisse utiliser directement ce code dans un background-image en variabilisant les attributs de type fill compatibles avec un préprocesseur comme SASS.

Et pour les gros volumes de SVG et un peu plus de performance web, une autre option (pour aller) un plus loin…

Exemple

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> <path fill="rgb(255,69,0)" d="M27,14H18V5a2,2,0,0,0-4,0v9H5a2,2,0,0,0,0,4h9v9a2,2,0,0,0,4,0V18h9a2,2,0,0,0,0-4Z"/> </svg>

Ce code affichera un pictogramme "+" orange. Une fois encodé, le XML fournira une chaine de caractères exploitable dans un background-image CSS, ce qui donnera :

background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E %3Cpath fill='rgb(255,69,0)' d='M27,14H18V5a2,2,0,0,0-4,0v9H5a2,2,0,0,0,0,4h9v9a2,2,0,0,0,4,0V18h9a2,2,0,0,0,0-4Z'/%3E %3C/svg%3E");

Note aux utilsateurs : dans l'optique de «partage», les fichiers soumis sont enregistrés de manière anonyme et accessibles à tout le monde. Les logos marqués ™ et © sont régulièrement supprimés.
Si vous ne souhaitez pas que votre fichier soit accessible, vous pouvez en demander la suppression ici.

Prévisualisation
nb: si la prévisualisation ne fonctionne pas, ne pas hûrler ! Il s'agit probablement d'un bug sur le SVG initial.
Si vous souhaitez participer, même modestement, au maintien du site et pour son usage, vous pouvez cliquer sur le joli bouton… ou scanner le QR code.
Un petit sou avec

Alternative SVG / CSS utilisant les identifiants SVG

Nous connaissons les «sprites» SVG classiques, avec l'utilisation de use. Cette méthode implique souvent de charger le code du SVG et des symbol au coeur même de la page HTML.
L'inconvénient de cette pratique (même si elle a des avantages…) est que ce fichier est présent dans toutes les pages du site, le plus souvent. En cas de mise à jour du sprite, il faut invalider le cache côté serveur (ou du CDN) et côté client.
Un autre petit souci est qu'il faut faire appel à un polyfill pour certains navigateurs et que cet usage devient compliqué lorsque l'on souhaite utiliser ce même fichier en propriété background-image dans un fichier CSS.

Imaginons les icones suivantes :

Séchage en machine à température modérée (60 °C maximum)
Séchage en machine à température modérée (80 °C maximum)
Séchage en machine interdit
Lavage en machine 30 °C, programme coton
Lavage en machine 30 °C, programme synthétique
Lavage en machine 30 °C, programme laine
Lavage en machine prohibé

Pour construire le SVG nécessaire, nous allons découper les icones et factoriser les éléments communs.
Nous avons donc besoin d'une bassine (4 fois) , d'une croix (2 fois) , d'une température de 30 °C (3 fois) , d'un point (3 fois) , d'un cercle (3 fois) , d'un carré (3 fois) , et enfin d'un trait (3 fois) .

Maintenant, nous allons assembler tout ce petit monde pour construire nos icones, avec pour effet de n'avoir qu'un seul symbol à mettre à jour en cas de modification graphique.
Commençons à construire notre SVG.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
            <defs></defs>
        </svg>
        

Maintenant, nous mettons notre belle bassine dans son symbol avec un identifiant.
A noter le fait de ne pas mettre de viewBox sur le symbol, partant du principe que toutes nos icones sortiront en 32x32 (nous le verrons à l'étape suivante).

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
            <defs>
                <symbol id="wash">
                    <path d="M30,6.15l-.54,2.66a4.73,4.73,0,0,1-2.33-1.17,5.89,5.89,0,0,0-4-1.52,5.79,5.79,0,0,0-4,1.52,4.48,4.48,0,0,1-3.11,1.22A4.4,4.4,0,0,1,13,7.64,5.87,5.87,0,0,0,9,6.12,5.81,5.81,0,0,0,5,7.64,4.66,4.66,0,0,1,2.6,8.84L2,6H0L4,26H28L32,6.17ZM26.41,24H5.6L2.86,10.31a6.08,6.08,0,0,0,3-1.47A4.48,4.48,0,0,1,9,7.61a4.41,4.41,0,0,1,3.11,1.22,6,6,0,0,0,8,0,4.55,4.55,0,0,1,6.2,0,6.31,6.31,0,0,0,2.93,1.47Z"/>
                </symbol>
            </defs>
        </svg>
        

Normalement, nous devrions nous arrêter là. Mais comme nous voulons utiliser ce SVG en ressource externe ET via des background-image, nous allons compléter notre fichier avec des balises view qui seront appelées via leur identifiant, suivies de balises use pointant sur les symboles à l'intérieur du même fichier.
Plus clairement, ça donne ceci :

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
            <defs>
                <symbol id="wash">
                    <path d="M30,6.15l-.54,2.66a4.73,4.73,0,0,1-2.33-1.17,5.89,5.89,0,0,0-4-1.52,5.79,5.79,0,0,0-4,1.52,4.48,4.48,0,0,1-3.11,1.22A4.4,4.4,0,0,1,13,7.64,5.87,5.87,0,0,0,9,6.12,5.81,5.81,0,0,0,5,7.64,4.66,4.66,0,0,1,2.6,8.84L2,6H0L4,26H28L32,6.17ZM26.41,24H5.6L2.86,10.31a6.08,6.08,0,0,0,3-1.47A4.48,4.48,0,0,1,9,7.61a4.41,4.41,0,0,1,3.11,1.22,6,6,0,0,0,8,0,4.55,4.55,0,0,1,6.2,0,6.31,6.31,0,0,0,2.93,1.47Z"/>
                </symbol>
                <symbol id="forbidden">
                    <polygon style="stroke:#000;stroke-miterlimit:10;stroke-width:0.5px;" points="30.35 29.61 16.71 16 30.32 2.35 29.61 1.65 16 15.29 2.35 1.68 1.65 2.39 15.29 16 1.68 29.65 2.39 30.35 16 16.71 29.65 30.32 30.35 29.61"/>
                </symbol>
                <symbol id="wash-30">
                    <path d="M11.12,21.49a3.93,3.93,0,0,1-2-.49A2.26,2.26,0,0,1,8,19.66l.81-.86a1.09,1.09,0,0,0,.19.48,2,2,0,0,0,.46.46,2.87,2.87,0,0,0,.7.36,3,3,0,0,0,.94.14,3.21,3.21,0,0,0,.78-.09,1.81,1.81,0,0,0,.63-.28,1.36,1.36,0,0,0,.41-.42,1.08,1.08,0,0,0,.16-.57,1.16,1.16,0,0,0-.76-1.07,5.2,5.2,0,0,0-2.1-.35H9.77V16.31h.45A4.61,4.61,0,0,0,12.11,16a1.05,1.05,0,0,0,.73-1,1,1,0,0,0-.15-.55,1.64,1.64,0,0,0-.38-.41,1.86,1.86,0,0,0-.54-.24,2.55,2.55,0,0,0-.61-.08,2.69,2.69,0,0,0-1.4.33,2.09,2.09,0,0,0-.79.77l-1-1a2.64,2.64,0,0,1,.55-.56,4,4,0,0,1,.76-.41,5.11,5.11,0,0,1,.89-.27,5,5,0,0,1,.94-.09,4.59,4.59,0,0,1,1.3.18,3.48,3.48,0,0,1,1,.51,2.68,2.68,0,0,1,.67.76,1.88,1.88,0,0,1,.24,1,1.64,1.64,0,0,1-.47,1.22,2.73,2.73,0,0,1-1.35.67,2.58,2.58,0,0,1,.85.28,2.18,2.18,0,0,1,.64.51,2,2,0,0,1,.41.67,2.07,2.07,0,0,1,.14.78,2,2,0,0,1-.29,1.05,2.57,2.57,0,0,1-.78.76,4,4,0,0,1-1.11.47,4.81,4.81,0,0,1-1.31.17Zm8.81,0a3.6,3.6,0,0,1-1.77-.44A4,4,0,0,1,16.89,20a4.61,4.61,0,0,1-.77-1.43,4.43,4.43,0,0,1,0-3.1A4.68,4.68,0,0,1,17,14a4,4,0,0,1,1.28-1,3.5,3.5,0,0,1,1.7-.4A3.45,3.45,0,0,1,21.7,13,4,4,0,0,1,23,14.12a4.57,4.57,0,0,1,.78,1.44,5.12,5.12,0,0,1,.25,1.5,4.83,4.83,0,0,1-1.1,3,4.45,4.45,0,0,1-1.29,1A3.69,3.69,0,0,1,19.93,21.5Zm-2.56-4.45a5,5,0,0,0,.18,1.13,3.33,3.33,0,0,0,.49,1,2.69,2.69,0,0,0,.78.76,2.11,2.11,0,0,0,1.11.29,2.07,2.07,0,0,0,1.13-.3,2.7,2.7,0,0,0,.79-.79,3.42,3.42,0,0,0,.46-1,4.28,4.28,0,0,0,.16-1.08,4.13,4.13,0,0,0-.17-1.13,3.33,3.33,0,0,0-.49-1,2.57,2.57,0,0,0-.79-.75,2,2,0,0,0-1.08-.3,2,2,0,0,0-1.14.31,2.59,2.59,0,0,0-.8.78,3.42,3.42,0,0,0-.46,1,4,4,0,0,0-.17,1.08Z"/>
                </symbol>
            </defs>
        
            <!-- on préfixe les IDs par `i-` pour uniformiser les appels -->
        
            <!-- affichage de la bassine  -->
            <view id="i-wash" viewBox="10 10 32 32"/>
            <use xlink:href="#wash" x="10" y="10" width="32" height="32" />
        
            <!-- affichage de la bassine et la croix, déplacée de 50px sur la même ligne  -->
            <view id="i-wash-forbidden" viewBox="60 10 32 32"/>
            <use xlink:href="#wash" x="60" y="10" width="32" height="32" />
            <use xlink:href="#forbidden" x="60" y="10" width="32" height="32" />
        
            <!-- affichage de la bassine et la température à 30°C, déplacée de 50px supplémentaires sur la même ligne  -->
            <view id="i-wash-30" viewBox="110 10 32 32"/>
            <use xlink:href="#wash" x="110" y="10" width="32" height="32" />
            <use xlink:href="#wash-30" x="110" y="10" width="32" height="32" />
        
            <!-- et ainsi de suite pour les symboles et views… -->
        
        </svg>
        

Le fichier complet avec quelques options supplémentaires (CSS, script) est accessible ici sample_xlinks.svg.
Pour illustrer l'intérêt, il permet de générer 43 icones à partir de 19 balises symbol.
Taille des données transférées ~5.7 ko (gzip), mise en cache côté client, centralisation des assets, maintenance facilitée, etc….

Mise en oeuvre

Pour l'exemple, nous affichons l'icone de séchage prohibé en machine dans les consignes d'entretien de linge.

Note : l'utilisation de ce type de sprites SVG permet de s'affranchir de la gestion des positionnements en background-image CSS.
Aspect non négligeable également, la possibilté d'appliquer un effet de lazyload puiqu'on n'utilise pas d'appel SVG mais une balise image classique. (voir ici).

  • Appel par <img src="/svg/sample_xlinks.svg#i-drying-forbidden" alt="" /> affichera 
  • Appel par <img src="/px.gif" alt="" class="drying-forbidden"/> affichera  avec la CSS ad hoc ci-dessous.
.drying-forbidden {
            background-image: url('/svg/sample_xlinks.svg#i-drying-forbidden');
            width: 1.75rem;
            height: 1.75rem;
            vertical-align: middle;
        }

Et gâteau sous la cerise : compatible IE9 et plus récents.
Aller… y'a plus qu'à !!
Si besoin ou remarque(s), ça se passe ici : contact

Si vous souhaitez participer, même modestement, au maintien du site et pour son usage, vous pouvez cliquer sur le joli bouton… ou scanner le QR code.
Un petit sou avec
Voir aussi…