Refactoring CSS : Optimisation de la taille et des performances (Partie 3)

Publié: 2022-03-10
Résumé rapide ↬ La base de code refactorisée devrait entraîner des performances similaires ou améliorées et une meilleure santé de la base de code. Après tout, si le déploiement de la base de code refactorisée entraîne des problèmes de chargement ou de performances, cela entraînera une baisse du trafic et des revenus. Heureusement, il existe de nombreuses techniques d'optimisation que nous pouvons appliquer pour résoudre les problèmes potentiels de taille de fichier et de performances.

Dans les articles précédents de cette série, nous avons couvert l'audit de la santé de la base de code CSS et la stratégie de refactorisation CSS incrémentielle, les tests et la maintenance. Indépendamment de l'amélioration de la base de code CSS au cours du processus de refactorisation et de sa facilité de maintenance et d'extension, la feuille de style finale doit être optimisée pour obtenir les meilleures performances possibles et la taille de fichier la plus faible possible.

Le déploiement de la base de code refactorisée ne devrait pas entraîner une dégradation des performances du site Web et une détérioration de l'expérience utilisateur. Après tout, les utilisateurs n'attendront pas indéfiniment que le site Web se charge. De plus, la direction sera insatisfaite de la baisse du trafic et des revenus causée par la base de code non optimisée, malgré les améliorations de la qualité du code.

Dans cet article, nous allons couvrir les stratégies d'optimisation CSS qui peuvent optimiser la taille des fichiers CSS, les temps de chargement et les performances de rendu. De cette façon, la base de code CSS refactorisée est non seulement plus maintenable et extensible, mais également performante et coche toutes les cases importantes à la fois pour l'utilisateur final et la direction.

Partie de : refactorisation CSS

  • Partie 1 : Refactorisation CSS : Introduction
  • Partie 2 : Stratégie CSS, tests de régression et maintenance
  • Partie 3 : Optimisation de la taille et des performances
  • Abonnez-vous à notre newsletter par e-mail pour ne pas manquer les prochaines.

Optimisation de la taille du fichier de feuille de style

L'optimisation de la taille du fichier se résume à supprimer les caractères inutiles et à formater et optimiser le code CSS pour utiliser différentes syntaxes ou propriétés abrégées afin de réduire le nombre total de caractères dans un fichier.

Optimisation et minification

L'optimisation et la minification CSS existent depuis des années et sont devenues un incontournable de l'optimisation frontale. Des outils comme cssnano et clean-css font partie de mes outils préférés en matière d'optimisation et de minification CSS. Ils offrent une grande variété d'options de personnalisation pour contrôler davantage la manière dont le code est optimisé et les navigateurs pris en charge.

Ces outils fonctionnent de manière similaire. Tout d'abord, le code non optimisé est analysé et transpilé en suivant les règles définies dans le fichier config. Le résultat est le code qui utilise moins de caractères mais conserve toujours la mise en forme (sauts de ligne et espaces).

 /* Before - original and unoptimized code */ .container { padding: 24px 16px 24px 16px; background: #222222; } /* After - optimized code with formatting */ .container { padding: 24px 16px; background: #222; }

Et enfin, le code optimisé transpilé est minifié en supprimant toute mise en forme de texte inutile . Selon la base de code et les navigateurs pris en charge définis dans la configuration, le code avec des préfixes de fournisseur obsolètes peut également être supprimé.

 /* Before - optimized code with formatting */ .container { padding: 24px 16px; background: #222; } /* After - optimized and minified code */ .container{padding:24px 16px;background:#222}

Même dans cet exemple de base, nous avons réussi à réduire la taille globale du fichier de 76 octets à 55 octets, ce qui a entraîné une réduction de 23 %. En fonction de la base de code, des outils d'optimisation et de la configuration, l'optimisation et la minification CSS peuvent être encore plus efficaces.

L'optimisation et la minification CSS peuvent être considérées comme une victoire facile en raison du gain significatif avec seulement quelques ajustements au flux de travail CSS. C'est pourquoi la minification doit être considérée comme l'optimisation des performances minimale et comme une exigence pour toutes les feuilles de style du projet.

Plus après saut! Continuez à lire ci-dessous ↓

Optimisation des requêtes multimédias

Lorsque nous écrivons des requêtes multimédias en CSS, en particulier lorsque nous utilisons plusieurs fichiers (PostCSS ou Sass), nous n'imbriquons généralement pas le code sous une seule requête multimédia pour un projet entier. Pour améliorer la maintenabilité, la modularité et la structure du code, nous écrivons généralement les mêmes expressions de requête multimédia pour plusieurs composants CSS.

Considérons l'exemple suivant d'une base de code CSS non optimisée.

 .page { display: grid; grid-gap: 16px; } @media (min-width: 768px) { .page { grid-template-columns: 268px auto; grid-gap: 24px; } } /* ... */ .products-grid { display: grid; grid-template-columns: repeat(2, 1fr); grid-gap: 16px; } @media (min-width: 768px) { .products-grid { grid-template-columns: repeat(3, 1fr); grid-gap: 20px; } }

Comme vous pouvez le voir, nous avons un @media (min-width: 768px) par composant pour une meilleure lisibilité et maintenance. Exécutons l'optimisation et la minification sur cet exemple de code et voyons ce que nous obtenons.

 .page{display:grid;grid-gap:16px}@media (min-width: 768px){.page{grid-template-columns:268px auto;grid-gap:24px}}.products-grid{display:grid;grid-template-columns:repeat(2,1fr);grid-gap:16px}@media (min-width: 768px){.products-grid{grid-template-columns:repeat(3,1fr);grid-gap:20px}}

Cela peut être un peu difficile à lire, mais tout ce que nous devons remarquer est la requête multimédia répétée @media (min-width: 768px) . Nous avons déjà conclu que nous voulons réduire le nombre de caractères dans une feuille de style et nous pouvons imbriquer plusieurs sélecteurs sous une seule requête multimédia, alors pourquoi le minificateur n'a-t-il pas supprimé l'expression dupliquée ? Il y a une raison simple à cela.

L'ordre des règles est important dans CSS, donc pour fusionner les requêtes multimédias dupliquées, les blocs de code doivent être déplacés. Cela entraînera une modification de l'ordre des règles, ce qui peut entraîner des effets secondaires indésirables dans les styles.

Cependant, la combinaison de requêtes multimédias pourrait potentiellement rendre la taille du fichier encore plus petite, en fonction de la base de code et de la structure. Des outils et des packages tels que postcss-sort-media-queries nous permettent de supprimer les requêtes multimédias en double et de réduire davantage la taille du fichier.

Bien sûr, il y a la mise en garde importante d'avoir une structure de base de code CSS bien structurée qui ne dépend pas de l'ordre des règles. Cette optimisation doit être prise en compte lors de la planification du refactoring CSS et de l'établissement de règles de base.

Je recommanderais de vérifier d'abord si les avantages de l'optimisation l'emportent sur les risques potentiels. Cela peut être facilement fait en exécutant un audit CSS et en vérifiant les statistiques de requête multimédia. Si c'est le cas, je recommanderais de l'ajouter plus tard et d'exécuter des tests de régression automatisés pour détecter les effets secondaires et les bogues inattendus qui pourraient en résulter.

Suppression du CSS inutilisé

Au cours du processus de refactorisation, il est toujours possible que vous vous retrouviez avec des styles hérités inutilisés qui n'ont pas été complètement supprimés ou que vous ayez des styles nouvellement ajoutés qui ne sont pas utilisés. Ces styles s'ajoutent également au nombre total de caractères et à la taille du fichier. Cependant, l'élimination de ces styles inutilisés à l'aide d'outils automatisés peut être quelque peu risquée car les outils ne peuvent pas prédire avec précision quels styles sont réellement utilisés.

Des outils comme purgecss parcourent tous les fichiers du projet et utilisent toutes les classes mentionnées dans les fichiers comme sélecteurs, juste pour pécher par excès de prudence et ne pas supprimer accidentellement les sélecteurs pour les éléments dynamiques injectés en JavaScript, entre autres cas potentiels. Cependant, purgecss offre des options de configuration flexibles comme solutions de contournement pour ces problèmes et risques potentiels.

Cependant, cette amélioration ne devrait être effectuée que lorsque les avantages potentiels l'emportent sur les risques . De plus, cette technique d'optimisation nécessitera un temps considérable pour l'installation, la configuration et les tests, et pourrait causer des problèmes imprévus sur toute la ligne, alors procédez avec prudence et assurez-vous que la configuration est à l'épreuve des balles.

Éliminer le CSS bloquant le rendu

Par défaut, CSS est une ressource bloquant le rendu, ce qui signifie que le site Web ne sera pas affiché à l'utilisateur tant que toutes les feuilles de style liées et leurs dépendances (polices, par exemple) n'auront pas été téléchargées et analysées par le navigateur.

Exemple de CSS bloquant le rendu avec feuille de style de police et dépendance de fichier de police
Exemple de CSS bloquant le rendu avec une feuille de style de police et une dépendance au fichier de police. (De web.dev sous licence Creative Commons Attribution 4.0) ( Grand aperçu )

Si le fichier de feuille de style a une taille de fichier importante ou plusieurs dépendances situées sur des serveurs tiers ou des CDN, le rendu du site Web peut être considérablement retardé en fonction de la vitesse et de la fiabilité du réseau.

La plus grande peinture de contenu (LCP) est devenue une mesure importante au cours des derniers mois. Le LCP n'est pas seulement important pour les performances, mais aussi pour le référencement - les sites Web avec de meilleurs scores LCP auront un meilleur classement des résultats de recherche. La suppression des ressources bloquant le rendu comme CSS est un moyen d'améliorer le score LCP.

Cependant, si nous différions le chargement et le traitement de la feuille de style, cela entraînerait un Flash Of Unstyled Content (FOUC) - le contenu serait immédiatement affiché à l'utilisateur et les styles seraient chargés et appliqués quelques instants plus tard. Ce commutateur peut sembler discordant et peut même dérouter certains utilisateurs.

CSS critique

Avec Critical CSS, nous pouvons nous assurer que le site Web se charge avec le minimum de styles dont l'utilisation est garantie sur la page lors de son rendu initial. De cette façon, nous pouvons rendre le FOUC beaucoup moins perceptible ou même l'éliminer dans la plupart des cas. Par exemple, si la page d'accueil comporte un composant d'en-tête avec navigation et un composant héros situé au-dessus du pli, cela signifie que le CSS critique contiendra tous les styles globaux et de composants nécessaires pour ces composants, tandis que les styles des autres composants de la page sera différé.

Ce CSS est intégré dans HTML sous une balise de style , de sorte que les styles sont chargés et analysés avec le fichier HTML. Bien que cela se traduira par une taille de fichier HTML légèrement plus grande (qui devrait également être réduite), tous les autres CSS non critiques seront différés et ne seront pas chargés immédiatement et le site Web s'affichera plus rapidement. Dans l'ensemble, les avantages l'emportent sur l'augmentation de la taille du fichier HTML.

 <head> <style type="text/css"><!-- Minified Critical CSS markup --></style> </head>

Il existe de nombreux outils automatisés et packages NPM, en fonction de votre configuration, qui peuvent extraire les CSS critiques et générer des feuilles de style différées.

Différer les feuilles de style

Comment fait-on exactement pour que le CSS soit non bloquant ? Nous savons qu'il ne doit pas être référencé dans l'élément d'en- head HTML lors du premier téléchargement de la page HTML. Demian Renzulli a décrit cette méthode dans son article.

Il n'existe pas (pour l'instant) d'approche HTML native pour optimiser ou différer le chargement des ressources bloquant le rendu. Nous devons donc utiliser JavaScript pour insérer la feuille de style non critique dans le balisage HTML après le rendu initial. Nous devons également nous assurer que ces styles sont chargés de manière non optimale (bloquant le rendu) si un utilisateur visite la page avec JavaScript non activé dans le navigateur.

 <!-- Deferred stylesheet --> <link rel="preload" as="style" href="path/to/stylesheet.css" onload="this.onload=null;this.rel='stylesheet'"> <!-- Fallback --> <noscript> <link rel="stylesheet" href="path/to/stylesheet.css"> </noscript>

Avec link rel="preload" as="style" s'assure que le fichier de feuille de style est demandé de manière asynchrone, tandis que le gestionnaire JavaScript onload s'assure que le fichier est chargé et traité par le navigateur après le chargement du document HTML. Un nettoyage est nécessaire, nous devons donc définir onload sur null pour éviter que cette fonction ne s'exécute plusieurs fois et ne provoque des rendus inutiles.

C'est exactement ainsi que Smashing Magazine gère ses feuilles de style. Chaque modèle (page d'accueil, catégories d'articles, pages d'articles, etc.) a un CSS critique spécifique au modèle intégré dans la balise de style HTML dans l'élément head , et une feuille de style main.css différée qui contient tous les styles non critiques.

Cependant, au lieu de basculer le paramètre rel , nous pouvons voir ici la requête multimédia passer du support d' print de faible priorité automatiquement différé à l'attribut de priorité élevée all lorsque la page a fini de se charger. Il s'agit d'une approche alternative, tout aussi viable, pour différer le chargement des feuilles de style non critiques.

 <link href="/css/main.css" media="print" onload="this.media='all'" rel="stylesheet">

Fractionnement et chargement conditionnel des feuilles de style avec des requêtes multimédias

Pour les cas où le fichier de feuille de style final a une taille de fichier importante même après l'application des optimisations susmentionnées, vous pouvez diviser les feuilles de style en plusieurs fichiers en fonction des requêtes multimédias et utiliser la propriété multimédia sur les feuilles de style référencées dans l'élément HTML du lien pour les charger de manière conditionnelle. .

 <link href="print.css" rel="stylesheet" media="print"> <link href="mobile.css" rel="stylesheet" media="all"> <link href="tablet.css" rel="stylesheet" media="screen and (min-width: 768px)"> <link href="desktop.css" rel="stylesheet" media="screen and (min-width: 1366px)">

De cette façon, si une approche axée sur le mobile est utilisée, les styles pour les grandes tailles d'écran ne seront pas téléchargés ou analysés sur les appareils mobiles qui pourraient fonctionner sur des réseaux plus lents ou peu fiables.

Pour rappel, cette méthode doit être utilisée si le résultat des méthodes d'optimisation mentionnées précédemment aboutit à une feuille de style avec une taille de fichier sous-optimale. Pour les cas courants, cette méthode d'optimisation ne sera pas aussi efficace ou percutante, selon la taille de la feuille de style individuelle.

Différer les fichiers de polices et les feuilles de style

Le report des feuilles de style de police (fichiers Google Font, par exemple) peut également être bénéfique pour les performances de rendu initiales. Nous avons conclu que les feuilles de style bloquent le rendu, tout comme les fichiers de police référencés dans la feuille de style. Les fichiers de police ajoutent également un peu de surcharge aux performances de rendu initiales.

Le chargement des feuilles de style de police et des fichiers de police est un sujet complexe et s'y plonger nécessiterait un tout nouvel article juste pour expliquer toutes les approches viables. Heureusement, Zach Leatherman a décrit de nombreuses stratégies viables dans ce guide complet impressionnant et a résumé les avantages et les inconvénients de chaque approche. Si vous utilisez Google Fonts, Harry Roberts a défini une stratégie pour le chargement le plus rapide des polices Google.

Si vous décidez de différer les feuilles de style de police, vous vous retrouverez avec Flash of Unstyled Text (FOUT). La page sera initialement rendue avec la police de secours jusqu'à ce que les fichiers de police différés et les feuilles de style aient été téléchargés et analysés, moment auquel les nouveaux styles seront appliqués. Ce changement peut être très perceptible et peut entraîner des changements de mise en page et dérouter les utilisateurs, selon le cas individuel.

Barry Pollard a décrit certaines stratégies qui peuvent nous aider à gérer le FOUT et a parlé de la prochaine fonctionnalité CSS d'ajustement de la taille qui fournira un moyen plus simple et plus natif de gérer le FOUT.

Optimisations côté serveur

Compression HTTP

En plus de la minification et de l'optimisation de la taille des fichiers, des actifs statiques tels que les fichiers HTML, CSS, JavaScript, etc. Des algorithmes de compression HTTP tels que Gzip et Brotli peuvent être utilisés pour réduire davantage la taille du fichier téléchargé.

La compression HTTP doit être configurée sur le serveur qui dépend de la pile technologique et de la configuration. Cependant, les avantages en termes de performances peuvent varier et peuvent ne pas avoir autant d'impact que la minification et l'optimisation standard des feuilles de style, car les navigateurs décompresseront toujours les fichiers compressés et devront les analyser.

Mise en cache des feuilles de style

La mise en cache des fichiers statiques est une stratégie d'optimisation utile. Les navigateurs devront toujours télécharger les fichiers statiques du serveur lors du premier chargement, mais une fois qu'ils seront mis en cache, ils seront chargés directement à partir de celui-ci lors des requêtes suivantes, ce qui accélérera le processus de chargement.

La mise en cache peut être contrôlée via l'en-tête HTTP Cache-Control au niveau du serveur (par exemple, en utilisant le fichier .htaccess sur un serveur Apache).

Avec max-age nous pouvons indiquer combien de temps le fichier doit rester en cache (en secondes) dans le navigateur et avec public , nous indiquons que le fichier peut être mis en cache par le navigateur et tout autre cache.

 Cache-Control: public, max-age=604800

Une stratégie de cache plus agressive et efficace pour les ressources statiques peut être obtenue avec une configuration immutable . Cela indique au navigateur que ce fichier particulier ne changera jamais et que toute nouvelle mise à jour entraînera la suppression de ce fichier et qu'un nouveau fichier avec un nom de fichier différent prendra sa place. C'est ce qu'on appelle le cache-busting .

 Cache-Control: public, max-age=604800, immutable

Sans une stratégie appropriée de contournement du cache, il existe un risque de perdre le contrôle des fichiers mis en cache sur le navigateur de l'utilisateur. Cela signifie que si le fichier devait changer, le navigateur ne pourra pas savoir qu'il doit télécharger le fichier mis à jour et ne pas utiliser le fichier en cache obsolète. Et à partir de ce moment, nous ne pouvons pratiquement rien faire pour résoudre ce problème et l'utilisateur sera bloqué avec le fichier obsolète jusqu'à son expiration.

Pour les feuilles de style, cela pourrait signifier que si nous devions mettre à jour les fichiers HTML avec un nouveau contenu et des composants nécessitant un nouveau style, ces styles ne s'afficheront pas car la feuille de style obsolète est mise en cache sans stratégie de contournement du cache et le navigateur ne le saura pas. il doit télécharger le nouveau fichier.

Avant d'utiliser une stratégie de mise en cache pour les feuilles de style ou tout autre fichier statique, des mécanismes efficaces de contournement du cache doivent être mis en œuvre pour empêcher les fichiers statiques obsolètes de rester bloqués dans le cache de l'utilisateur. Vous pouvez utiliser l'un des mécanismes de contrôle de version suivants pour le contournement du cache :

  • Ajout d'une chaîne de requête au nom du fichier.
    Par exemple styles.css?v=1.0.1. Cependant, certains CDN peuvent complètement ignorer ou supprimer la chaîne de requête du nom de fichier, ce qui fait que le fichier reste bloqué dans le cache de l'utilisateur et ne se met jamais à jour.
  • Modification du nom du fichier ou ajout d'un hachage.
    Par exemple styles.a1bc2.css ou styles.v1.0.1.css. C'est plus fiable et efficace que d'ajouter une chaîne de requête au nom du fichier.

CDN ou auto-hébergement ?

Le réseau de diffusion de contenu (CDN) est un groupe de serveurs répartis géographiquement qui sont couramment utilisés pour la livraison fiable et rapide d'actifs statiques tels que des images, des vidéos, des fichiers HTML, des fichiers CSS, des fichiers JavaScript, etc.

Bien que les CDN puissent sembler être une excellente alternative aux actifs statiques auto-hébergés, Harry Roberts a effectué des recherches approfondies sur le sujet et a conclu que les actifs auto-hébergés sont plus bénéfiques pour les performances.

« Il y a vraiment très peu de raisons de laisser vos ressources statiques sur l'infrastructure de quelqu'un d'autre. Les avantages perçus sont souvent un mythe, et même s'ils ne l'étaient pas, les compromis n'en valent tout simplement pas la peine. Le chargement d'actifs provenant de plusieurs origines est manifestement plus lent. »

Cela étant dit, je recommanderais d'auto-héberger les feuilles de style (feuilles de style de police incluses, si possible) par défaut et de passer au CDN uniquement s'il existe des raisons viables ou d'autres avantages à le faire.

Audit de la taille et des performances des fichiers CSS

WebPageTest et d'autres outils d'audit de performances similaires peuvent être utilisés pour obtenir un aperçu détaillé du processus de chargement du site Web, de la taille des fichiers, des ressources de blocage du rendu, etc. Ces outils peuvent vous donner un aperçu de la façon dont votre site Web se charge sur une large gamme d'appareils — d'un ordinateur de bureau fonctionnant sur un réseau haut débit à des smartphones bas de gamme fonctionnant sur des réseaux lents et peu fiables.

Faisons un audit de performance sur un site Web mentionné dans le premier article de cette série - celui avec les 2 Mo de CSS minifié.

Tout d'abord, nous examinerons la répartition du contenu pour déterminer quelles ressources occupent le plus de bande passante. D'après les graphiques suivants, nous pouvons voir que les images prennent la plupart des demandes, ce qui signifie qu'elles doivent être chargées paresseusement. Dans le deuxième graphique, nous pouvons voir que les feuilles de style et les fichiers JavaScript sont les plus volumineux en termes de taille de fichier. C'est une bonne indication que ces fichiers doivent être minifiés et optimisés, refactorisés ou divisés en plusieurs fichiers et chargés de manière asynchrone.

Deux graphiques montrant la répartition du contenu par type MIME
Répartition du contenu par type MIME (sur la première vue). ( Grand aperçu )

Nous pouvons tirer encore plus de conclusions des graphiques Web Vitals. En jetant un coup d'œil au graphique Largest Contentful Paint (LCP), nous pouvons obtenir un aperçu détaillé des ressources bloquant le rendu et de leur incidence sur le rendu initial.

Nous pourrions déjà conclure que la feuille de style du site Web aura le plus d'impact sur le LCP et les statistiques de chargement. Cependant, nous pouvons voir des feuilles de style de police, des fichiers JavaScript et des images référencées dans les feuilles de style qui bloquent également le rendu. Sachant que nous pouvons appliquer les méthodes d'optimisation susmentionnées pour réduire le temps LCP en éliminant les ressources bloquant le rendu.

le plus grand tableau de peinture contente
Un graphique pour la plus grande peinture de contenu qui se produit à 8561 ms. Remarquez l'ampoule orange sur la chronologie dans la liste des ressources - ces ressources bloquent le rendu. ( Grand aperçu )

Conclusion

Le processus de refactorisation n'est pas terminé lorsque la santé et la qualité du code ont été améliorées et lorsque les faiblesses et les problèmes de la base de code ont été corrigés. La base de code refactorisée devrait entraîner des performances identiques ou améliorées par rapport à la base de code héritée.

Les utilisateurs finaux ne devraient pas rencontrer de problèmes de performances ou de longs temps de chargement à partir de la base de code refactorisée. Heureusement, il existe de nombreuses méthodes pour s'assurer que les bases de code sont à la fois robustes et performantes - des méthodes simples de minification et d'optimisation aux méthodes plus complexes comme l' élimination des ressources bloquant le rendu et le fractionnement du code.

Nous pouvons utiliser divers outils d'audit des performances tels que WebPageTest pour obtenir un aperçu détaillé des temps de chargement, des performances, des ressources bloquant le rendu et d'autres facteurs afin de pouvoir résoudre ces problèmes rapidement et efficacement.

Partie de : refactorisation CSS

  • Partie 1 : Refactorisation CSS : Introduction
  • Partie 2 : CSS Refactoring : stratégie, tests de régression et maintenance
  • Partie 3 : CSS Refactoring : Optimisation de la taille et des performances
  • Abonnez-vous à notre newsletter par e-mail pour ne pas manquer les prochaines.

Les références

  • «CSS bloquant le rendu», Ilya Grigorik
  • « Différer les CSS non critiques », Demian Renzulli
  • "Un guide complet des stratégies de chargement de polices", Zach Leatherman
  • "Une nouvelle façon de réduire l'impact du chargement des polices : les descripteurs de police CSS", Barry Pollard
  • "Auto-hébergez vos actifs statiques", Harry Roberts
  • "Optimisez le chargement et le rendu de WebFont", Ilya Grigorik