Une suite d’icônes dans un fichier svg

On a redesigné le site de codeur·euses en Liberté ! C’est vrai que depuis 8 ans, ça commençait à prendre un peu la poussière. C’est un peu plus frais. Il y a encore quelques morceaux en mouvement, n’hésitez pas à nous signaler les petits bugs.

Le plus visible, c’est le nouveau logo 🙀:

Le nouveau logo codeur·euses en liberté

Il ressemble à celui d’avant, mais son style reflète bien notre usage des dernières technologies.

Le logo de Codeur·euses en liberté sur une feuille dans une machine à écrire.
En route pour le futur

C’était aussi l’occasion pour moi de faire un peu de frontend, c’est-à-dire du CSS, du HTML, et du JS1SVG. Voici donc le premier post d’une série de trois, où je raconte les petits hacks, les techniques « modernes », et les bonnes ou mauvaises pratiques découvertes à l’occasion.

Comment faire une suite d’icônes dans un unique fichier svg

Un des chantiers à l’occasion du redesign a été de simplifier la gestion des icônes du site, en permettant de les teinter avec le texte. Il s’agit du problème habituel : une suite de glyphes/symboles/icônes, qu’on veut pouvoir utiliser dans le corps du texte ou dans des boutons.

Je vous livre déjà la conclusion : ne faites pas de polices d’icônes, c’était déjà pénible il y a dix ans, et ça fait longtemps que ça ne sert plus à rien.

Le problème

Avant le redesign, on utilisait déjà une poignée d’icônes, tirée de FontAwesome. Ça ressemblait à ça:

.icon::before {
  display: inline-block;
  margin-inline-end: 0.5ch; 
  content: ' '; /* a single unbreakable space */
  width: 1.5ch;
  background: no-repeat center center;
  background-size: contain;
}

.icon-envelope::before { background-image: url('../img/fa-envelope.svg') }
.icon-github::before   { background-image: url('../img/fa-github.svg') }
.icon-gitlab::before   { background-image: url('../img/fa-gitlab.svg') }
.icon-heart::before    { background-image: url('../img/fa-heart.svg') }
.icon-key::before      { background-image: url('../img/fa-key.svg') }
.icon-mastodon::before { background-image: url('../img/fa-mastodon.svg') }
.icon-web::before      { background-image: url('../img/fa-globe.svg') }

Avec autant de fichiers svg que d’icônes, et autant de règles css à répéter.
Dans le html, ça s’utilisait ainsi :

<p>
  Contactez-nous par email à
  <a class="icon icon-envelope" href="mailto:bonjour@codeureusesenliberte.fr">bonjour@codeureusesenliberte.fr</a>
</p>

Ça marchait pas mal :

Mais en mode sombre, rien n’allait plus:

Par ailleurs, d’un point de vue accessibilité2, c’était pas génial : il n’y avait pas trace de l’image dans le DOM. On pouvait faire mieux.

Teinter des svg avec la couleur du texte

Faire de la couleur en svg, c’est pas très compliqué, c’est selon le cas l’attribut fill ou l’attribut stroke. Par exemple, ce fragment de html:

<blockquote style="color: darkblue">
  Du texte bleu avant un rond orange: 
  <svg width=10px height=10px>
    <circle cx="5" cy="5" r="5" fill="orange"/>
  </svg>
</blockquote>

Donne cela:

Du texte bleu avant un rond orange: 

On peut varier, la couleur du texte et la couleur du rond indépendamment:

Du texte bleu avant un rond bleu: 

Mais ce qu’on veut, c’est que le svg soit dessiné avec la couleur du texte. L’astuce pour consiste à utiliser le mot-clé currentcolor:

<blockquote style="color:darkgreen">
  Du texte bleu avant un rond de la même couleur : 
  <svg width=10px height=10px>
    <circle cx="5" cy="5" r="5" fill="currentcolor" /> <!-- ici -->
  </svg>
</blockquote>

Ça donne ça :

Du texte bleu avant un rond de la même couleur : 

Tous les svg dans le même fichier

Si vos symboles se limitent à des petits ronds, félicitations, c’est fini ! Comme le svg des symboles est souvent nettement plus complexe et est composé d’un ou plusieurs path avec leur syntaxe un poil absconse, on préfère éviter de les répéter dans le DOM à chaque utilisation.

svg use à la rescousse

Le langage SVG permet de déclarer des symboles et de leur donner un identifiant:

<svg>
<symbol id="icon_name">
  ...
</symbol>
</svg>

On peut ensuite les utiliser avec l’élément use:

<svg><use href="#icon_name"/></svg>

Tous les symboles svg peuvent être réunis dans un seul fichier. Ça donne ça, avec l’icône de mastodon, chargée depuis le fichier icons.svg:

<svg width=20px height=20px><use href="/img/icons.svg#fa-mastodon"/></svg>
Un éléphant ça trompe énormément.

Quelques détails techniques pour finir:

Comme je le disais au début, ce n’est pas une technique moderne ! C’est supporté par tous les navigateurs depuis une bonne dizaine d’années. Malheureusement, un bon paquet des collections d’icônes largement utilisées sont basées sur l’utilisation de polices de symboles. C’est d’ailleurs pour ça que FontAwesome s’appelle comme ça — mais ça ne nous empêche pas d’utiliser les glyphes de FontAwesome dans des svg.3

C’est tout pour cette fois-ci: la prochaine fois, on parlera de variables css et de design adaptatif sans media queries.


  1. D’accord, il y a un poil de javascript, mais c’est pour débugguer le CSS. ↩︎

  2. Et sémantique, mais c’est un peu pareil. ↩︎

  3. FontAwesome “free” est distribué en CC BY SA 4.0. J’ai le vague sentiment que le gros du travail de FontAwesome en 2024 est de faire de l’outillage et de la gestion de paquets, pas de dessiner des icônes. Gardons ce débat pour un autre jour. ↩︎