Comme tout site Web, Hopwork cherche à optimiser l’expérience de ses visiteurs, notamment en réduisant au maximum le temps écoulé avant que le site ne soit affiché et utilisable. Deuxième effet kiss-cool, ce temps est également évalué par les moteurs de recherche et participe au classement du site Web dans leurs résultats. Nous allons vous présenter une technique appelé Critical Css et un outil open-source que nous avons créé pour aider 🙂

Ce qu’on peut faire, pour quel résultat

Il existe de nombreuses techniques – non exclusives – pour réduire le temps de premier affichage :

  • servir les pages très vite : serveurs et code performants, serveurs proches du visiteur ;
  • limiter le nombre de ressources servies ;
  • limiter le contenu de ces ressources au strict nécessaire (pas de code “mort”) ;
  • compresser les ressources servies ;
  • utiliser un CDN ;
  • placer les règles de style concernant la partie de la page qui sera visible en premier, directement en ligne dans la balise <head> de la page (critical-path CSS).

Le test Google PageSpeed par exemple incite à l’utilisation de cette dernière astuce. Chez Hopwork, nous avons encore du travail à faire sur certains des points cités, mais nous avons notamment mis en place cette technique, ce qui nous a fait gagner 7 points au Google PageSpeed pour le desktop, et 17 points pour le mobile !

Critical Css : En pratique

Quand le style est chargé sous forme d’un fichier CSS à part (cas classique), on voit le site Hopwork s’afficher par morceaux plutôt disgracieux, avant que le navigateur ne redessine tout une deuxième fois, à l’arrivée du fichier CSS, déplaçant ainsi le contenu que le visiteur peut avoir commencé à lire. En fait, nous avions même mis en place un masque sur tout le contenu pour empêcher nos utilisateurs de voir cela. Le site restait ainsi “blanc” pendant un moment, avant d’apparaître tout beau :

hopwork home blank
Hopwork pendant le chargement du style
hopwork home loaded
Premier affichage quand tout est prêt

Quand le style de la partie “critique” est présent en ligne dans le HTML, le site est rendu directement avec l’apparence désirée, tout du moins pour le haut de la page. Le reste sera rendu proprement plus tard, suite au chargement du fichier CSS. Bon, chez Hopwork tout n’est pas encore parfait : on voit clairement que les polices arrivent plus tard et entraînent un reflow de l’affichage :

Concrètement, quand on a la fibre cela parait un peu inutile, car tout se charge très vite. Mais pour tous ceux qui surfent avec leur tablettes ou mobiles en 3G ou 4G, ou même avec certaines connexions ADSL campagnardes, cela fait une différence ! Et pour Google aussi, puisqu’il nous décerne désormais une bien meilleure note.

Des outils limités

À présent qu’on a vu ce que l’on pouvait attendre de la technique, passons à la mise en oeuvre. Tous les outils existants se basent sur le même principe : charger une page et l’afficher avec la résolution demandée (typiquement dans un navigateur headless tel que phantomjs), puis extraire toutes les règles CSS s’appliquant aux éléments immédiatement visibles sans faire défiler la page. Cette partie de CSS devra ensuite être insérée dans les pages en question, souvent via un autre outil.

Critical

L’outil le plus populaire pour extraire le critical-path CSS de votre site est critical du prolifique Addy Osmani. Il s’intègre dans vos scripts de build, typiquement via grunt ou gulp. Le problème : l’outil requiert d’avoir une version statique des pages pour lesquelles extraire la CSS critique, ce qui n’est pas forcément évident pour un site au contenu dynamique.

Chez Hopwork, nous l’avons utilisé un temps en contournant la difficulté : nous avions écrit un scénario Selenium dont le but n’était pas de tester le site, mais de le lancer avec du contenu approprié en base, puis de naviguer sur les pages à optimiser afin d’en extraire le HTML, pour ensuite le donner à manger à critical, et enfin insérer la CSS résultante dans nos templates HTML (ouf).

Autant vous dire tout de suite que ce n’était pas très pratique, ce processus prenant trop de temps à notre goût (environ 2 minutes), étant parfois instable (Selenium…), et les données à générer pouvant parfois être assez nombreuses si l’on voulait avoir des pages ressemblant suffisamment à la production pour que le style extrait soit le bon.

En ligne

D’autres outils comme criticalcss.com vous laissent entrer l’adresse d’une page Web et vous donnent le critical-path CSS, mais aucune API n’est disponible pour automatiser ça proprement, donc ça n’est en pratique pas utilisable pour un site déployé régulièrement.

Google PageSpeed

Enfin, Google propose un module PageSpeed pour les serveurs Apache et Nginx, capable de générer le critical-path CSS pour les pages proxifiées, et de le réintroduire à la volée dans ces pages. Mais là encore, un certain nombre de limitations en font un outil insuffisant. Déjà, le module se désactive si le client utilise Internet Explorer. Ensuite, il va traiter toutes les requêtes, même si le navigateur aurait entre-temps eu l’opportunité de mettre en cache les fichiers CSS servis, ce qui permettrait de ne pas alourdir les requêtes suivantes avec du contenu CSS inséré dans le HTML. Et il y a encore quelques autres particularités qui ne nous ont pas satisfaits.

Arrive CCSSS

Quand on a essayé ce qui existait déjà, et que rien n’est satisfaisant, c’est qu’il est temps de créer ses propres outils.

Évidemment, nous n’avions pas spécialement de temps à accorder à cela, donc l’idée était :

  • de faire le minimum nécessaire, vite et bien
  • sans réinventer la roue
  • qu’il ne soit à l’avenir plus question de préparation compliquée pour traiter une nouvelle page
  • que le résultat soit vraiment ce qui est utile en production
  • et ce pour des affichages de différentes résolutions (desktop, mobile, etc.)

Et donc nous avons créé l’outil ccsss (Critical-path CSS Service, et non, aucune honte :-), et ajouté un peu de plomberie dans notre application.

Ccsss fait à peu près la même chose que critical, mais sous forme d’un Web service exposant une API HTTP, via laquelle on va pouvoir soumettre des tâches d’extraction de CSS critique, et récupérer le résultat. L’API permet de tout configurer, et notamment de demander une CSS faisant l’affaire pour différentes résolutions. Comme critical et d’autres outils, il se base sur penthouse, et il peut être intégré à un processus de build, mais nous l’avons plutôt prévu pour être utilisé sur un environnement live.

Ainsi, pour nous, le processus devient le suivant :

  1. L’application Web Hopwork est déployée.
  2. Elle envoie alors des requêtes d’extraction de CSS critique à ccsss.
  3. Ccsss notifie notre application quand la CSS est prête. (Ça va en fait assez vite dans notre cas, mais nous avons trouvé ce design préférable pour le cas général. Et il est aussi possible de poller l’API pour savoir si le résultat est prêt.)
  4. Notre application demande la CSS résultante à ccsss.
  5. L’application stocke la CSS en mémoire, associée aux URLs pour lesquelles elle doit servir cette CSS en ligne.
  6. Quand les pages des URLs en question sont servies, l’application insère la CSS dans le résultat (ou pas, voir plus bas).

Évidemment, comme écrit plus haut, cela nécessite également un peu de plomberie dans notre application, mais rien de bien méchant (faire des requêtes HTTP et stocker le résultat, on s’en sort). Et cela permet même d’aller un peu plus loin à moindre coût.

Vers l’infini et au-delà

Bon OK, là je survends un peu le truc 🙂

À présent que nous avons un peu de logique dans notre appli pour gérer cette CSS critique, nous sommes libres d’améliorer un peu le bousin.

Déjà, nous avons fait en sorte de ne livrer la CSS critique dans le HTML que si le client ne l’a jamais reçue. Pour toutes les requêtes suivantes, il a déjà le fichier CSS complet en cache, donc inutile d’alourdir la page. À cette fin nous avons ajouté un petit cookie associant un ensemble de pages au hash SHA1 de la CSS correspondante. Au premier chargement d’une page d’un ensemble donné, le SHA1 qui va bien est ajouté au cookie. Lors des chargements suivants, le SHA1 sera comparé à celui en mémoire dans l’application, et s’il n’a pas changé, aucune CSS critique ne sera livrée.

Ensuite, nous nous sommes fendus d’un petit écran d’administration pour configurer tout ça, faire des tests facilement sur notre environnement de pré-prod, désactiver le procédé pour des pages rencontrant des soucis imprévus en production, etc. Encore une fois, pas de temps à perdre, donc c’est brut, mais ça fait le taf et ça n’a pris qu’une heure ou deux :

admin cpcss
L’admin en question. C’est brut, nous ne vous avons pas menti 🙂

Pour finir

Voilà, c’est la fin de cette petite histoire… Pour ceux qui auraient encore faim, n’hésitez pas à poser des questions via les commentaires, ou a partager votre expérience sur le sujet.
Enfin, l’accent n’a pas été trop mis dessus au cours de l’article, mais notre outil ccsss est totalement libre et dispo sur npm, donc si ça vous titille, n’hésitez surtout pas à l’essayer, l’adopter, voire à le câliner en lui proposant des améliorations.

One thought on “Critical CSS : Pour quelques millisecondes de moins

Leave a Reply

Your email address will not be published. Required fields are marked *