Optimiser le chargement des icones
lundi 7 août 2023
Il y a un mois, jâai poussĂ© des changements sur les icones dâun site en production qui nous a fait gagnĂ© 8% sur le FCP de nos utilisateurices.
Pourtant, quand on a commencĂ© Ă ajouter des icones, ils nâavaient aucun impact. Comment en sommes-nous arrivĂ©s lĂ âŻ? Dans cet article je vous prĂ©sente les diffĂ©rentes mĂ©thodes par lesquelles nous sommes passĂ©es, leurs avantages, leurs inconvĂ©nients et je terminerai avec un petit laius sur comment le mettre en place dans votre projet.
Cet article fait partie dâune sĂ©rie dâarticles en lien avec la Web Performance oĂč jâessaye dâapporter des mĂ©thodes pour analyser la rapiditĂ© de vos pages et des solutions concrĂštes Ă des problĂšmes rĂ©currents :
- Pourquoi améliorer le LCP de vos pages�
- Analyser le comportement réseau pour améliorer FCP et LCP
- Optimiser les images sur le web : checklist des bonnes pratiques
- Optimiser le chargement des fonts
- Optimiser la gestion des icĂŽnes (vous ĂȘtes ici)
- Comment diagnostiquer et corriger du Cumulative Layout Shift (CLS)�
- Quelles techniques pour diminuer la quantité de JavaScript� (bientÎt)
- Quelles métriques suivre en dehors des Core Web Vitals� (bientÎt)
- Et plus encore đ«¶
Si vous avez besoin dâune entrĂ©e en matiĂšre plus rapide, je suis aussi disponible en freelance pour vous accompagner sur des problĂ©matiques de performance.
Etape 1Â : Une image par icone
Généralement quand on commence à développer un site web, on a encore aucun outil en place et on a juste une maquette à disposition. Alors le plus naturel est de commencer par utiliser une balise <img>
.
<img src="/icone/home.svg" alt="Accueil" />
Histoire quâelle ne soit pas pixelisĂ©e, on va prĂ©fĂ©rer le format SVG. On le passe un petit coup dans SVGOMG, un outil pour optimiser et rĂ©duire la taille de nos fichiers SVG. On vĂ©rifie que celle-ci est correctement mise en cache au niveau rĂ©seau. Et on envoie en prod.
Attention à la surcharge réseau
Cependant, le problĂšme de cette approche est quâau fur et Ă mesure cela risque de surcharger votre rĂ©seau. CâĂ©tait trĂšs vrai Ă lâĂ©poque de HTTP1. Beaucoup vous diront que ce nâest plus le cas pour HTTP2 mais ce nâest pas vrai. Au delĂ dâun certain nombre de requĂȘtes simultanĂ©es des problĂšmes se manifestent :
- le navigateur ne sait plus comment prioriser les requĂȘtes (quel fichier doit ĂȘtre tĂ©lĂ©chargĂ© en premierâŻ?)
- le navigateur peut perdre du temps en orchestration (cela se manifeste par beaucoup de hachure et une bandewidth saturée dans votre cascade réseau)
- chaque fichier est gzippĂ© de maniĂšre indĂ©pendante : or, ces algorithmes de compression sont dâautant plus efficaces que vos fichiers sont gros et rĂ©pĂ©titifs. Vous gagnerez donc en bande passante en fusionnant vos icones plutĂŽt quâen les tĂ©lĂ©chargeant sĂ©parĂ©ment
Lâobjectif est donc de trouver une maniĂšre de fusionner les icones en un fichier.
đĄ Si vous nâĂȘtes pas en mesure de changer de mĂ©thode de chargement dâicones, pour rĂ©gler cette problĂ©matique : assurez vous que vos icones qui ne sont pas directement visibles ont lâattribut
loading="lazy"
, et vĂ©rifiez que vous ĂȘtes bien en HTTP2. Vous aurez adressĂ© le plus gros du problĂšme.
Interaction limitée
Une autre problĂ©matique de cette mĂ©thode est sa capacitĂ© Ă changer dâimage Ă la volĂ©e.
Normal | Hover / Focus |
---|---|
|
|
<img>
SVG)Si vous voulez par exemple faire en sorte que votre icone change de couleur au survol, vous allez devoir :
- ajouter du JavaScript pour changer lâURL de votre image Ă la volĂ©e (ce qui provoquera des lenteurs lors de la transition parce quâil faut tĂ©lĂ©charger la nouvelle image)
- ou utiliser des astuces CSS Ă base de Sprite
- ou passer par filter en CSS (ex: de base votre image est colorée, et vous la passez en noir en appliquant
filter: grayscale(100%) brightness(0);
)
Câest somme toute assez compliquĂ©, et il existe des mĂ©thodes pour simplifier cela.
Etape 2Â : les fonts dâicones
La premiĂšre solution Ă cela est lâutilisation de fonts dâicones.
A mon Ă©poque (jâai le droit de dire ça aprĂšs 30 ans, nâen dĂ©plaise aux vieux đ€), la lib que tout le monde utilisait pour mettre des icones sur son site Ă©tait Font Awesome. CâĂ©tait facile Ă installer, ça permet dâajouter en un clin dâoeil les icones.
Comment ça marche�
-
Un fichier de font qui permet dâassocier un caractĂšre Ă un icone.
@font-face { font-family: 'Font Awesome 6 Free'; font-display: block; src: url(/icons/font-awesome.woff2) format('woff2'); }
-
Une classe CSS qui permet de choisir quel caractĂšre afficher (ici le caractĂšre
\f015
correspond Ă un icone đ ).fa { font-family: 'Font Awesome 6 Free'; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; display: var(--fa-display, inline-block); font-style: normal; font-variant: normal; line-height: 1; text-rendering: auto; } .fa-house::before { content: '\f015'; }
-
une balise HTML vide qui reprend la classe dĂ©finie en CSS pour choisir lâicone Ă afficher
<i class="fa fa-house"></i>
Avec ces trois Ă©lĂ©ments vous avez ce quâil vous faut pour gĂ©rer des icones sur votre site. Ca fonctionne bien, et lâavantage supplĂ©mentaire par rapport aux balises <img>
est que vous pouvez facilement configurer la couleur de vos icones en modifiant la couleur du texte en CSSÂ :
:hover,
:focus {
color: red;
}
Cependant, cette mĂ©thode aussi vient avec son lot dâinconvĂ©nients.
Pourquoi Ă©viter les fonts dâiconesâŻ?
Plus vous ajoutez des icones, plus vous avez des problĂšmes
Si votre base dâicone grossit (ou que vous utilisez une base toute faite) : les fichiers dâicones deviennent vite Ă©normes. A lâheure de la rĂ©daction de lâarticle, les icones gratuits de Font Awesome, câest 148KBâŻ! Sans compter le fichier CSS qui vient rajouter 24KB de plus.
Il est certes possible dâappliquer les mĂȘmes mĂ©thodes de subsetting que lâoptimisation des fonts, mais le concept pousse quand mĂȘme Ă utiliser une seule et mĂȘme source (le fichier woff2) qui grossiera tant que vous avez des icones Ă ajouter.
Dâailleurs, dans un de mes projets, nous passions par fontastic pour gĂ©nĂ©rer la font. Au bout dâun certain nombre dâicones, la gĂ©nĂ©ration commençait Ă crasher parce que nous avions trop dâicones. Peut-ĂȘtre que ça venait du fait quâon avait juste trop dâicones, mais câest quand mĂȘme lâindice dâun problĂšme đ
Lenteur dâaffichage et gestion des fallbacks
Autre problĂšme : vos icones ne sont pas visibles tant que le fichier de font nâa pas Ă©tĂ© chargĂ©. Elles peuvent donc mettre du temps Ă venir, dâautant plus si vous nâavez pas preload la font.
Plus gĂȘnant, Ă une Ă©poque, la propriĂ©tĂ© font-display
nâexistait pas. Du coup, si la font nâarrivait pas Ă se charger, on se retrouvait avec des caractĂšres bizarres affichĂ©s Ă lâĂ©cran (ex : âî
â).
Conflit avec des outils dâaccessibilitĂ©
Dans la majoritĂ© des documentations de font dâicones, vous devrez fouiller pour trouver la mention dâaccessibilitĂ©. Pourtant, une icone, comme une image mĂ©rite dâĂȘtre correctement labelisĂ©e. Cela est possible en adoptant ce HTML :
<!-- Si le picto est redondant avec un texte à cÎté -->
<i class="fa fa-house" aria-hidden="true"></i> Accueil
<!-- Si l'icone est seule -->
<span>
<i class="fa-solid fa-house" title="Accueil" aria-hidden="true"></i>
<span class="sr-only">Accueil</span>
</span>
En prenant le coup de main, câest donc possible de correctement renseigner les labels pour les icones. Cependant, lĂ oĂč câest plus handicapant, câest le fait que ce soit une font. En effet, certaines personnes surchargent les fonts utilisĂ©es dans les navigateurs pour en faciliter la lecture (ex : OpenDyslexic). Votre CSS ne sera donc plus maĂźtre de la font utilisĂ©e et risque dâafficher des lettres ou des caractĂšres unicodes Ă la place des icones.
Etape 3Â : Inline SVG Symbol
Ok, les font icones : pas ouf.
Si on accumule les contraintes, on cherche donc une solution :
- qui Ă©vite des tonnes de requĂȘtes
- qui ne passe pas par une font pour des questions de poids et dâaccessibilitĂ©
- qui soit facile Ă changer lors dâune interaction
Est-ce quâon pourrait utiliser du SVG directement dans la pageâŻ?
<svg height="1em" viewBox="0 0 24 24" aria-labelledby="icon-title-ajx18rtJBjSu">
<title id="icon-title-ajx18rtJBjSu">Accueil</title>
<path d="M0 24 v-24 h24 a12,12 11 0,1 0,24 a12,12 11 0,1 -24,0z" fill="currentColor" />
</svg>
Ainsi notre page HTML ne contient que les icones dont elle a besoin et cela a lâavantage de se charger immĂ©diatement, pas besoin de requĂȘte supplĂ©mentaire.
Cette mĂ©thode rĂ©pond Ă la totalitĂ© des contraintes ci dessus. Par contre, si un icone est utilisĂ© plusieurs fois dans votre page, le HTML sera alourdi dâautant vu que vous allez devoir rĂ©pĂ©ter le SVG. Câest Ă nuancer parce que cette duplication sera certainement compensĂ©e par gzip. Mais câest toute de mĂȘme dommage alors quâon peut faire mieux.
Utilisation des <defs>
en SVG
En effet, en SVG il existe une mĂ©thode pour Ă©viter de dupliquer du code : lâutilisation des <symbol>
avec <use>
. Voyons comment ça marche.
Au sein de votre page HTML (généralement en fin de page, et en display: none
), vous devez définir une balise <svg>
qui va contenir une liste de définitions (<defs>
). Cette liste de définitions est généralement utilisée par votre image en SVG pour décrire des clipPath
, des filtres ou des dégradés. Mais dans notre cas, nous allons utiliser des <symbol>
. Grosso modo, un symbol est un sous SVG que lâon va pouvoir rĂ©fĂ©rencer ailleurs. Pour chaque icone, nous allons donc devoir ajouter une nouvelle balise <symbol>
 :
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="M0 24 v-24 h24 a12,12 11 0,1 0,24 a12,12 11 0,1 -24,0z" fill="currentColor" />
</symbol>
<symbol id="icon-user" viewBox="0 0 24 24"><!-- ... --></symbol>
</defs>
</svg>
Pour générer cette balise, il va falloir :
- Passer le SVG de lâicone initial dans SVGOMG afin de sâassurer quâil est bien optimisĂ©
- Ouvrir ensuite lâonglet âMarkupâ pour y lire la balise
<svg>
- Récupérer la viewBox de celle-ci et la mettre en attribut de votre balise
<symbol>
- RĂ©cupĂ©rer tout ce quâil y a Ă lâintĂ©rieur de la balise
<svg>
et le mettre Ă lâintĂ©rieur de votre balise<symbol>
- Définir enfin un attribut
id
sur votre balise<symbol>
(ex:id="icon-home"
) Attention il est important que cet id soit unique dans toute votre page.
Une fois fait, passons Ă lâaffichage de lâicone dans notre page. En effet, pour lâinstant, vous nâavez fait que dĂ©finir des rĂšgles dâaffichage, mais vous nâavez pas indiquĂ© au navigateur oĂč lâafficher. Pour cela, nous allons dĂ©finir une nouvelle balise SVG que nous pouvons mettre dans notre HTML :
<svg height="32" width="32" viewBox="0 0 24 24" aria-labelledby="icon-title-ajx18rtJBjSu">
<title id="icon-title-ajx18rtJBjSu">Accueil</title>
<use href="#icon-home"></use>
</svg>
Celle-ci est trĂšs similaire au SVG Inline que nous avions Ă©crit plus haut. La seule diffĂ©rence est que nous remplaçons lâintĂ©rieur du <svg>
(Ă lâexception du <title>
) par une balise <use>
. Son attribut href
permet en quelque sorte dâimporter le symbol
en y faisant référence via son id
. Il se construit de la mĂȘme maniĂšre quâune ancre dans une page.
Ainsi, le partie lourde du SVG (<path>
, etc.) nâest pas rĂ©pĂ©tĂ©e dans votre page HTML, et vous pouvez facilement dĂ©finir de nouveaux icones au fur et Ă mesure.
đĄ Vous nâaimez pas dĂ©finir la liste des
symbol
manuellementâŻ? NâhĂ©sitez pas Ă fouiller internet pour trouver lâoutil qui vous le gĂ©nĂ©rera pour vous. Câest par exemple le cas de Icon Pipeline.HonnĂȘtement, vu que câest 5min de manipulation et quâon nâajoute pas des icones tous les 4 matins, ce nâest pas une tĂąche que jâai automatisĂ© sur les projets oĂč je travaille. Mais ça dĂ©pend de la taille de votre Ă©quipe et du type de profils qui manipulent le code.
La partie que lâon a automatisĂ© est la gĂ©nĂ©ration du SVG de lâicone lui mĂȘme (celui qui contient la balise
<use>
). NâhĂ©sitez pas Ă abstraire cette partie derriĂšre une fonction ou un composant qui automatisera la gĂ©nĂ©ration dâids, forcera lâutilisation dâun texte alternatif et de la dĂ©finition dâune taille.
Quels bénéfices aux SVG Symbol pour gérer les icones�
Câest quand mĂȘme pas mal de manutention. Alors quels avantages est-ce que ça apporteâŻ?
Modifier la couleur du SVG en CSS
Un des avantages majeurs des fonts dâicones est la possibilitĂ© de changer la couleur de lâicone au survol.
Câest aussi possible avec les Symbol SVG. En effet, vous nây avez peut-ĂȘtre pas prĂȘtĂ© attention, mais dans le <path>
jâai mis lâattribut fill="currentColor"
. currentColor
est en fait une valeur en CSS qui permet de dire au navigateur dâutiliser la couleur courante du texte.
Ainsi, si votre icone est dans une balise <a>
et que vous ajoutez le CSS suivant, alors au survol votre icone passera de bleu Ă rouge.
a {
color: blue;
}
a:hover,
a:focus {
color: red;
}
Vous pouvez mĂȘme aller plus loin et manipuler plus en profondeur le style de votre SVG directement en CSSÂ :
/* Par défaut, seule la bordure de l'icone est visible, en noir */
a svg {
stroke: #000000;
fill: transparent;
}
/* Au survol et au focus, la bordure devient rouge, et l'intérieur se remplit en rouge */
a:hover svg,
a:focus svg {
stroke: red;
fill: red;
}
Câest donc une mĂ©thode trĂšs versatile qui pourra vous amener bien plus loin dans lâanimation de vos icones.
Les icones sont immédiatement visibles
Etant donnĂ© que lâicone est prĂ©sent dans le HTML, le navigateur est en mesure de parser votre SVG et lâafficher directement. LâinconvĂ©nient cependant est que le navigateur va du coup le parser de maniĂšre synchrone. Si vous avez beaucoup dâicones, cela peut finir par impacter vos performance. Dans notre cas, il sâagissait de 8% de FCP.
PossibilitĂ© dâimporter uniquement les symbol
dont a besoin la page
Etant donné que la liste de symbol
est gĂ©nĂ©rĂ©e directement dans le HTML, il est possible de nây mettre que les symbol
dont la page a besoin et pas un de plus. Je le nuancerai en disant que ça dĂ©pend beaucoup de votre tooling. Dans notre cas, la liste de symbol a grossi jusquâĂ atteindre 46 icones. CâĂ©tait moins que nos icon fonts, mais câĂ©tait quand mĂȘme beaucoup (trop).
Quels inconvénients aux SVG Symbol�
Plus vous avez dâicones, plus vous ralentirez le chargement de votre page.
MĂȘme si cette mĂ©thode a beaucoup de bĂ©nĂ©fices, jâai commencĂ© Ă mentionner ci-dessus que cela pouvait poser des problĂšmes dĂšs lors que le nombre dâicones diffĂ©rents utilisĂ©s dans votre page augmente (les fameux -8% de LCP quand nous avons arrĂȘtĂ© dâutiliser cette mĂ©thode).
Ce sera dâautant plus vrai si vos pages prĂ©sentent beaucoup dâinteractivitĂ©. En effet, vous vous demandez peut-ĂȘtre comment on a pu se retrouver avec 46 icones diffĂ©rents sur chaque page. A tout cassĂ©, au premier affichage, nous en avions peut-ĂȘtre 10 maximum. DâoĂč venaient les 36 autresâŻ? Ils Ă©taient utiles Ă des modales globales. Nos outils nâĂ©taient pas configurĂ©s pour importer des icones de maniĂšre asynchrone dans la page. Ainsi, les icones dont nous avions besoin pour les modales de connexion, dâinscription, de newsletter, etc. Ă©taient tous importĂ©s au chargement de la page plutĂŽt quâau chargement de la modale.
đĄ Je tiens Ă prĂ©ciser que ce problĂšme venait principalement de la maniĂšre dont nous utilisions cette technique. Absoluement rien ne vous empĂȘche de configurer vos outils pour gĂ©rer lâajout de maniĂšre asynchrone. Cependant, plutĂŽt que dâaller vers une solution technique complexe en JS, fetch, Ajax & co, lâĂ©tape 4 montrera comment rĂ©gler cette problĂ©matique simplement.
Les icones ne sont pas en cache
Contrairement aux fonts, les icones ne sont pas chargĂ©s via un fichier externe. La consĂ©quence est donc quâĂ chaque nouvelle page HTML, vos utilisateurices devront retĂ©lĂ©charger la liste dâicones SVG au mĂȘme titre quâils tĂ©lĂ©chargerons le HTML. Dans notre cas, ça reprĂ©sentait entre 10 et 30kB supplĂ©mentaires par page, soit parfois jusquâĂ 30% de poids de page supplĂ©mentaire.
Etape 4Â : Remote SVG Symbol
Notre nouvelle solution devrait donc ajouter les contraintes suivantes :
- qui Ă©vite des tonnes de requĂȘtes
- qui ne passe pas par une font pour des questions de poids et dâaccessibilitĂ©
- qui soit facile Ă changer lors dâune interaction
- + qui puisse ĂȘtre tĂ©lĂ©chargĂ© Ă la demande (ex : Ă lâouverture dâune modale)
- + qui puisse ĂȘtre mis en cache entre chaque page
Pour rĂ©gler ces nouvelles contraintes, la solution est de faire en sorte que les icones soient rĂ©cupĂ©rĂ©s de maniĂšre externe. En effet, si nous reprenons la maniĂšre dont on a Ă©crit le SVG Ă lâendroit oĂč on veut afficher lâicone, nous avions une balise use
:
<use href="#icon-home"></use>
Celle-ci passe par un attribut href
parce quâen rĂ©alitĂ© on nâest pas obligĂ© de dĂ©finir une ancre dans la page courante. On peut aller chercher la dĂ©finition SVG Ă une autre URL.
Ainsi plutĂŽt que de mettre votre SVG qui contient la liste de <defs>
au sein de la page, nous allons lâenregistrer dans son propre fichier:
<!-- /images/icon-defs.svg -->
<svg xmlns="http://www.w3.org/2000/svg">
<defs>...</defs>
</svg>
A ce moment lĂ , nous pourrons changer notre balise use
afin quâelle utilise la nouvelle URL:
-<use href="#icon-home"></use>
+<use href="/images/icon-defs.svg#icon-home"></use>
GrĂące Ă cela, la liste dâicone se retrouve en dehors de la page HTML et pourra donc ĂȘtre tĂ©lĂ©chargĂ© et mis en cache au mĂȘme titre que nâimporte quel asset externe.
â ïž Attention toutefois, il y a une contrainte forte : votre SVG distant doit impĂ©rativement ĂȘtre hĂ©bergĂ© sur le mĂȘme nom de domaine. Si ce nâest pas le cas, les navigateurs vont considĂ©rer que câest une faille de sĂ©curitĂ© et votre icone ne marchera pas.
Ca tombe bien, câest de toute façon une recommendation si vous voulez que votre site soit performant. Cela sera une raison de plus pour migrer vos assets sur votre nom de domaine principal si ce nâest pas dĂ©jĂ le cas.
En vrai, il semble y avoir une mĂ©thode alternative qui existe si vraiment vous nâavez pas la maĂźtrise de vos noms de domaines. Cependant, elle offre moins de libertĂ© sur la gestion du lazyloading & des changements de couleur Ă lâinteraction.
đĄ Comment est-ce que cela se comporte dans le cas des modales/tabs/dropdownâŻ?
Je vous parlais des problĂšmes dâinteractivité : on ne veut tĂ©lĂ©charger les icones que quand ils sont visibles. Si le HTML de votre modale nâest pas prĂ©sent initialement dans votre page, alors le fichier nĂ©cessaire Ă lâaffichage de son icone (ex :
icon-modal-defs.svg
) ne sera pas téléchargé. Il existe toutefois une petite subtilité ici. Si votre HTML existe déjà dans votre page mais est endisplay: none
, alors votre fichier dâicones sera quand mĂȘme tĂ©lĂ©chargĂ©.Ce nâest gĂ©nĂ©ralement pas quelque chose auquel vous serez confrontĂ© avec des frameworks modernes tels que React, Vue ou mĂȘme des solutions alternatives telles que Simulus/Turbo ou htmx. Mais si vous nâavez pas dâautres choix que dâavoir le HTML dĂ©jĂ prĂ©sent dans votre page, essayez de lâentourer dâune balise
<template>
. Cela aura lâavantage de rendre tout le HTML Ă lâintĂ©rieur de celle-ci inerte. Le navigateur ne parsera donc pas le SVG, et donc ne tĂ©lĂ©chargera pas le fichier rĂ©fĂ©rencĂ© par la balise<use>
.Câest de toute façon une bonne pratique parce que cela indiquera Ă votre navigateur quâil nâa pas besoin de parser cette partie de la page pour pouvoir afficher le reste du contenu.
Quelles nouvelles opportunités offrent les Remote SVG Symbol�
Séparation en plusieurs fichiers
Lâavantage de cette mĂ©thode est que vous pouvez rapidement sĂ©parer vos dĂ©finitions dâicones : il vous faut crĂ©er diffĂ©rents sets dâicones (ex : icon-global-defs.svg, icon-product-defs.svg, etc.) et modifier lâURL de la balise use
en conséquence.
Optimisation des icones critiques
Dans votre site, certains icones sont plus importants que dâautres. Vous avez par exemple certainement des icones dans votre menu que vous voulez afficher le plus rapidement. Mais les icones de rĂ©seau sociaux dans votre footer, un peu moins.
Avec cette solution, vous pouvez à nouveau gérer la priorisation de vos ressources.
Par exemple, vous pouvez faire en sorte que vos icones critiques restent en inline (en gĂ©nĂ©ral il y en a entre 2 et 5, ça nâalourdira pas de maniĂšre significative votre page). Pour cela, vous pouvez rester sur lâĂ©tape 3 uniquement pour ces icones. (Câest la solution que nous avons choisi dans le projet sur lequel je travaille.)
Ou alors, si la mise en cache est importante pour vous, vous pouvez considĂ©rer que ces icones feront partie dâun fichier icon-critical-defs.svg
que vous pourrez preload dans votre page afin dâaugmenter sa prioritĂ© de tĂ©lĂ©chargement.
Lazyloading des icones non critiques
A lâinverse, pour les icones qui sont beaucoup plus loin dans votre page, si vous mesurez que les Remote SVG Symbol ralentissent le chargement de votre page, nâhĂ©sitez pas Ă mettre en place une mĂ©thode de lazyloading. Malheureusement, il nâen existe pas de native Ă ce jour qui mimiquerai le comportement de loading="lazy"
sur une balise img
.
Mais vous pourriez imaginer mettre en place un mécanisme en JavaScript. Cela pourrait ressembler à  :
const lazyloadIconObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const useTags = entry.target.querySelectorAll('use[data-href]');
useTags.forEach((tag) => {
tag.setAttribute('href', tag.dataset.href);
});
lazyloadIconObserver.unobserve(entry.target);
}
});
});
const lazyIcons = document.querySelectorAll('svg.lazy-icon');
lazyIcons.forEach((icon) => {
lazyloadIconObserver.observe(icon);
});
Il vous faudrait alors changer lâendroit oĂč lâicone est affichĂ© ainsi :
-<svg height="32" width="32" viewBox="0 0 24 24" aria-labelledby="icon-title-ajx18rtJBjSu">
+<svg class="lazy-icon" height="32" width="32" viewBox="0 0 24 24" aria-labelledby="icon-title-ajx18rtJBjSu">
<title id="icon-title-ajx18rtJBjSu">Accueil</title>
- <use href="#icon-home"></use>
+ <use data-href="/images/icon-defs.svg#icon-home"></use>
</svg>
Comment mettre en place ces méthodes quand je code en React�
JusquâĂ maintenant, je vous ai montrĂ© comment le principe de base fonctionne : quel est le HTML/CSS que vous aurez besoin dâajouter dans votre page pour que ça fonctionne. Cependant, selon votre niveau dâaisance avec le tooling que vous utilisez, peut-ĂȘtre que la mise en place sera douloureuse.
Câest dâautant plus vrai quâune pratique assez rĂ©pandue dans lâĂ©cosystĂšme React est dâutiliser un loader webpack pour transformer votre SVG en composant React/JSX.
La consĂ©quence, comme le montre Jason âdevelopitâ Miller dans son tweet, est que vous pouvez vous retrouver avec votre SVG Ă la fois dans votre HTML et dans votre JS. Dans le cas quâil a trouvĂ©, 50% du JS Ă©tait en fait du SVG, soit 125KB, avec les consĂ©quences en terme de performance qui vont avec. Oops.
Pour Ă©viter ces problĂšmes, vous devrez donc configurer votre bundler pour faire en sorte que votre SVG soit traitĂ© comme une image classique. Ainsi, dans votre code, quand vous importerez le SVG qui contient la liste de dĂ©finitions, vous ne rĂ©cupĂ©rerez pas le contenu du SVG, mais une URL oĂč il sera accessible. Cette mĂȘme URL dont on a besoin avec la mĂ©thode Remote SVG Symbol.
Pour Webpack (5+), vous aurez besoin de modifier votre configuration pour configurer les fichiers SVG en tant que asset/ressource
.
// webpack.config.js
const config = {
// âŠ
module: {
rules: [
// âŠ
{
test: /\.svg/,
type: 'asset/resource'
}
]
}
};
Pour Vite, câest dĂ©jĂ le comportement par dĂ©faut.
Ensuite, dans votre code React, vous pourrez écrire vos Icons de cette façon :
import IconDefs from './home-icon-defs.svg';
const Icon = ({ icon, title, size }) => {
/* J'inclue ici la gestion du texte alternatif de l'icone */
const randId = Math.random() * Number.MAX_SAFE_INTEGER;
const titleId = `icon-title-${randId}`;
const pixelSize = size === 'big' ? 32 : 24;
return (
<svg height={pixelSize} width={pixelSize} viewBox="0 0 24 24" aria-labelledby={titleId}>
<title id={titleId}>{title}</title>
{/* Mais la partie qui nous intéresse est surtout ce use */}
<use href={`${IconDefsUrl}#icon-${icon}`}></use>
</svg>
);
};
// âŠ
<Icon icon="home" title="Accueil" size={32} />;
Ainsi, vous utilisez bel et bien un use
et votre quantitĂ© de JS ne se retrouve pas pĂ©nalisĂ©e par le nombre dâicones que vous avez dans votre SVG.
Pour approfondir cette partie, nâhĂ©sitez pas Ă jeter un oeil Ă Breaking Up with SVG-in-JS in 2023 (EN).
Récapitulatif
Ok donc je vous ai montrĂ© 4 façons de faire des icones. Chacune a ses avantages et inconvĂ©nients et comme dâhabitude il nây a pas de silver bullet.
Si on devait résumer tout ça dans une matrice de décision :
- Si lâicone est utilisĂ© une seule fois dans votre page,
- Si cet icone est critique ou a besoin de changer de couleur lors dâune interaction,
- âĄïž utiliser le SVG en inline dans le HTML
- Si non,
- âĄïž utiliser une balise
<img>
- âĄïž utiliser une balise
- Si cet icone est critique ou a besoin de changer de couleur lors dâune interaction,
- Si lâicone est utilisĂ©e plusieurs fois,
- Si lâicone est critique
- âĄïž utiliser des Inline SVG Symbol
- Si lâicone nâest pas critique,
- Sâil est possible dâhĂ©berger du SVG sur votre propre domaine
- âĄïž utiliser des Remote SVG Symbol
- Si non,
- âĄïž Essayez de convaincre trĂšs fort votre admin sys de lâimportance dâavoir le mĂȘme domaine pour vos assets
- âĄïž Ou passez par un fallback avec des CSS mask
- âĄïž Ou utilisez des Inline SVG Symbol
- Sâil est possible dâhĂ©berger du SVG sur votre propre domaine
- Si lâicone est critique
- Si vous utilisez une font dâicone,
- âĄïž repartez en haut de cette matrice et choisissez une autre mĂ©thode. Vos utilisateurices vous remercieront.
Ce quâil faut aussi retenir, câest que tant que vous avez une quantitĂ© limitĂ©e dâicones, utiliser une balise SVG inline ou une balise <img>
sera certainement largement suffisant. NâhĂ©sitez donc pas Ă mesurer votre site avant de vous lancer dans des optimisations prĂ©maturĂ©es.
Vous avez du mal à déterminer quelle est la meilleure solution pour vous ou sur quels chantiers de performance vous lancer� Contactez-moi. Nous pouvons certainement travailler ensemble afin de rendre votre site rapide et améliorer votre taux de conversion.
Si vous avez trouvĂ© tout cela fort intĂ©ressant et ĂȘtes curieuse·x de connaĂźtre la suite, nâhĂ©sitez pas Ă me suivre ou Ă me poser des questions sur Mastodon ou Twitter. Notamment, dans mon prochain article, je parlerai des diffĂ©rentes stratĂ©gies pour diminuer votre quantitĂ© de JavaScript.
Pour les plus habitué·e·s dâentre vous, sachez que je publierai cette suite dans 2 semaines, ne pouvant pas assurer la rĂ©daction la semaine prochaine. Je vous souhaite un bel Ă©tĂ© et de bonnes vacances Ă celleux qui en ont et vous dit Ă trĂšs vite â±ïž
Si vous voulez suivre mes publications, il paraĂźt que j'ai un feed RSS, Mastodon et un Twitter.
Si vous pensez à d'autres méthodes que vous voudriez que je mette en place (pigeon voyageur, avion en papier, etc.), n'hésitez pas à me les proposer :)