Le chargement parfait des styles CSS
J'essaye de charger les styles CSS de la façon qui me semble la plus optimisée possible avec Jekyll
Avec l'aide d'astuces Liquid, je demande à Jekyll d'includer uniquement les blocs de styles CSS utilisés dans la page et de les afficher directement dans la balise HEAD
Le problème
Je veux pouvoir afficher le site le plus rapidement possible au visiteur sans avoir de chargement de fichiers superflux. Sans avoir à demander au navigateur de parser des informations CSS qui ne servent à rien dans la page en cours (donc pas de fichier global qui contient l’ensemble des styles du site). Je cherche à donner au visiteur seulement ce dont il a besoin au moment où il en a besoin pour afficher la page en cours.
Il faut garder en tête que le parsage et la prise en compte des styles CSS demande des ressources et de la mémoire au navigateur. Plus on lui en envoie, et plus c’est long sur les devices lents et/ou anciens.
Pour plus d’accéssibilité, je veux que mon document HTML soit validé W3C. Les styles CSS doivent donc être placés dans une balise STYLE
, dans la balise HEAD
Le tout doit être minifié et décommenté pour gagner quelques ko supperflus.
La solution doit être extensible. Je dois pouvoir avoir autant de templates, layout et feuilles de style que je veux.
J’utilise Jekyll, je dois pouvoir faire ça facilement avec des tags Liquid.
En bref, n’avoir qu’un fichier HTML à charger qui contient le contenu HTML ainsi que les styles necessaires placés dans la balise HEAD. De cette façon, le contenu CSS est gzippé avec le reste du fichier HTML par le serveur web. On se retrouve avec très peu de données à transférer.
Ma solution
Structure de fichiers
Pour que ce soit plus pratique pour moi, je créé un fichier common.html
qui contient l’ensemble de page html (de <html>
à </html>
) dans laquelle viendra se glisser le contenu du layout. Et de la même façon, je créé un fichier common.css
qui va contenir le CSS qui sera utilisé sur toutes les pages du site.
Si j’ai un fichier html que je risque d’inclure dans mon contenu un peu partout (dans un layout, ou bien simplement directement dans un post), alors je créé un fichier CSS du même nom. Exemple : video.html
, video.css
Pour chacun de mes templates, je créé un fichier CSS du même nom (s’il y a besoin d’y associer un CSS indépendant). Exemple : post.css
, posts.css
Ca donne ceci :
_includes/
common.html
common.css
post.css
posts.css
video.html
video.css
_layouts/
default.html
post.html
posts.css
Au niveau des layouts
Dans mon layout, la première chose que je fais, c’est de capturer les styles CSS du layout en cours dans une variable generated_css
:
<!-- _layouts/post.html (1/3) -->
{% capture generated_css %}
{{ generated_css }}
{% include posts.css %}
{% endcapture %}
(je concatène avec une éventuelle variable generated_css
existante pour permettre d’ajouter tous les styles utilisés dans la page. Ici ça ne servira pas, mais comme ça, j’utilise la même formule partout)
Ensuite, je capture l’ensemble de mon contenu dans une variable generated_content
:
<!-- _layouts/post.html (2/3) -->
{% capture generated_content %}
<section class="post">
[...]
</section>
{% endcapture %}
… à la suite de quoi, j’include mon fichier common.html
<!-- _layouts/post.html (3/3) -->
{% include common.html %}
Mon fichier common.html
va alors recevoir les deux variable generated_css
et generated_content
. Il n’aura qu’à les placer au bon endroit de la page :
<!-- _include_/common.html -->
<html>
<head>
<style>
{{ generated_css }}
</style>
</head>
<body>
{{ generated_content }}
</body>
</html>
Au niveau des posts et des pages
Au niveau des posts et pages, c’est un peu différent. Si je créé une variable generated_css
directement dans le contenu, elle ne sera pas transmise au layout. Je dois donc mettre l’information dans la configuration. Par exemple, pour cette page, je charge le style CSS qui me permet d’afficher des blocs de code avec coloration syntaxique. J’ajoute donc la variable YML contains_code
comme ceci :
‑‑‑
# 2021-09-07-my-blog-post.md
layout: post
contains_code: true
‑‑‑
Hello world :
```
<b>Hello world</b> is bold
```
… et au niveau de mon fichier common.html
, je peux alors indiquer que si contains_code
est à true
, alors je charge le style CSS pour la coloration syntaxique du code (le fichier _includes/code.css
par exemple).
<!-- _include_/common.html -->
{% if page.contains_code == true %}
{% capture generated_css %}
{{ generated_css }}
{% include code.css %}
{% endcapture %}
{% endif %}
<html>
[...]
</html>
Encore plus extensible…
La solution ci-dessus fonctionne bien. Par contre, c’est assez difficilement extensible. Je suis obligé d’ajouter une condition dans common.html
pour chaque feuille de style envisageable.
Pour avoir un résultat plus extensible, je peux ajouter un tag html directement dans le contenu de MarkDown de mon post qui ressemble à ceci :
<!--INCLUDE_CSS code.css END_INCLUDE_CSS-->
Et ensuite, dans mon fichier common.html
, je peux lui demander de trouver l’ensemble de ces tags qui se trouve dans le contenu de ma page (dans la variable generated_content
), d’en extraire le nom du fichier à inclure, de les lister, de retirer les doublons et d’ajouter leur contenu à la variable generated_css
:
<!-- _include_/common.html -->
{% assign CSS_list = "" %}
{% assign CSS_blocs = generated_content | split: "<!--INCLUDE_CSS" %}
{% for CSS_bloc in CSS_blocs %}
{% assign CSS_bloc_name_array = CSS_bloc | split: "END_INCLUDE_CSS-->" %}
{% assign CSS_bloc_name_size = CSS_bloc_name | size %}
{% assign CSS_bloc_name = CSS_bloc_name_array[0] | strip %}
{% if CSS_bloc_name_size > 1%}
{% assign CSS_list = CSS_list | append: "," | append: CSS_bloc_name %}
{% endif %}
{% endfor %}
{% assign CSS_list = CSS_list | split: "," | uniq %}
{% for CSS_inc in CSS_list %}
{% if CSS_inc !="" %}
{% capture generated_css %}
{{ generated_css }}
{% include {{ CSS_inc }} %}
{% endcapture %}
{% endif %}
{% endfor %}
<html>
[...]
</html>
Ce coup-ci, on est pas mal. Ne reste plus qu’à minifier tout ça. Avec Jekyll, j’utilise le plugin jekyll-minifier
avec l’option compress_css: true
et remove_comments: true
. De cette façon, je me retrouve avec une balise <style>
bien remplie et bien minifiée. Et mes tags perso <!--INCLUDE_CSS code.css END_INCLUDE_CSS-->
disparaissent du code en production.
Avantage collatéral
Je peux ajouter des balises Liquid dans mes feuilles de style. Pour par exemple définir une couleur dans mon fichier _config.yml
et l’utiliser dans mon code CSS :
a{
color:{{ site.color }};
}
Autres méthodes
Je pense qu’il est possible de faire ça avec SASS, mais je le maîtrise moins.
Quoi qu’il en soit, je suis plutôt content du résultat.
J’espère que ça vous aura aidé !