Dans la track web du FOSDEM 2025, nous avions vu la session « Tight mode, how browser really load web pages ». Contrairement à une idée reçue : prenez une page web et chargez-la dans les principaux navigateurs (Chromium/Chrome, Safari, Firefox). Le temps de chargement ne sera pas identique et surtout, les mécaniques internes pour charger une page ne seront pas les mêmes ni dans le même ordre. Cela signifie que le comportement des navigateurs n'est pas identique, ce qui engendre un problème de cohérence et de performances.
![](../themes/icons/grey.gif)
Robin Marx, l’intervenant de la session, met en avant l’effet cascade. Dans les faits, le navigateur va charger en deux étapes les différents contenus avec des décalages temporels. Cet effet cascade explique pourquoi une page web ne s’affiche pas instantanément et d’un seul tenant. Il faut toujours avoir en tête qu’une page web classique contient en réalité des dizaines d’éléments différents : les protocoles et éléments serveurs (DNS, SSL), HTML, CSS, JavaScript, les images, les polices, les différents types de médias, etc. Quand on détaille encore plus, il y a le type du document, la taille, le temps de chargement et surtout la notion de priorité.
Ce qui est sidérant, quand on ne fouille pas dans les DevTools, c’est de voir le comportement radicalement différent pour charger une page HTML exactement identique. Le comportement de Chrome propose des cascades de chargement plutôt cohérentes, alors que Safari a un premier chargement frôlant les 3ms avant de charger le reste des éléments. Firefox cherche à charger un maximum d’éléments en même temps au risque de provoquer un long délai pour les éléments les plus critiques (+2,5 ms).
![](../themes/icons/grey.gif)
Par exemple, si votre code JavaScript est retardé dans son chargement et sa compilation, le rendu est automatiquement retardé, voire bloqué. Un des problèmes vient des priorités attribuées à chaque élément. Nous trouvons du low, du high et du highest. Dans un même bloc d’éléments, nous pouvons trouver plusieurs priorités.
L’analyse du <head> permet de voir que :
- les CSS sont en priorité très haute
- les scripts JavaScript varient de priorité basse à haute
- les polices de caractères : priorité moyenne
Cela signifie que le navigateur prendra, théoriquement, les éléments les plus prioritaires en premier pour aller à la priorité la plus basse, au risque de bloquer le bon affichage à cause de l’ordre de traitement des éléments.
Comme le fait remarquer Robin, les serveurs n’écoutent pas ou pas assez les navigateurs. Souvent, le navigateur a une suite de traitements définie et claire, alors que les serveurs backend font un peu ce qu’ils veulent. Parfois, c’est une alternance d’éléments qui sont envoyés, provoquant un engorgement côté front, donc côté navigateur. L’exemple le plus criant est NodeJS : terrible pour les performances des pages. HTTP/2 et HTTP/3 tentent de remettre de l’ordre dans l’envoi des éléments d’une page…
Mais on comprend que le navigateur fait aussi ce qu’il veut : il récupère les ressources des pages, mais c’est lui qui va hiérarchiser les ressources et leur traitement et parfois, il ne tient pas compte des priorités ni de l’ordre imposé par le backend.
Le tight mode : indispensable mais le navigateur fait ce qu'il veut !
Pour tenter de corriger ce problème et améliorer les performances de chargement, il existe le Tight mode que l’on pourrait traduire par "mode serré". Il est disponible sur Chrome / Chromium et Safari, mais pas sur Firefox. Problème : ce mode se comporte différemment entre Chrome et Safari ! Officiellement : on vous simplifie la vie mais dans la réalité, pas trop…
En faisant simple : le tight mode réarrange les ressources à sa guise, il prend tout ce qui est marqué comme priorité très élevée / élevée et moyenne. Tout le reste est laissé de côté et non chargé dans le mode serré… jusqu’à ce que ce qui est traité par le tight mode soit réellement traité. Cela signifie que tout ce qui n’est pas pris en charge par ce mode est bloqué et ne se charge pas. C’est seulement après le chargement des ressources prioritaires que les ressources en priorité basse sont autorisées à être chargées et traitées ! Nous sommes donc dans la seconde cascade de chargement de la page web.
Dans la documentation du mode serré sur Chrome, il est dit ceci :
« Chrome charge les ressources en 2 phases :
- Le mode serré est la phase initiale et contraint les ressources à priorité basse à être chargées quand tous les autres scripts et éléments présents dans le head sont exécutés
- les ressources à faible priorité ne sont uniquement chargées que s’il y a moins de 2 requêtes en cours au moment où elles (les ressources basses) sont découvertes par le navigateur… »
Bref, le navigateur veut bien des priorités basses mais elles sont traitées quand le navigateur en a le temps… Depuis Chrome 117, le navigateur introduit 2 requêtes de priorité moyenne à s’exécuter en même temps.
Par exemple, si vous avez des scripts JS et des images, les scripts sont traités en priorité haute en parallèle. Les images seront chargées seulement après la fin de l’exécution des scripts. Dans l’exemple donné, les scripts prennent 2,74 secondes ! À la fin du traitement, le tight mode n’agit plus et laisse donc la place aux images qui sont en priorité basse… Sauf que… si vous avez des images en priorité moyenne et d’autres en priorité basse, les images en priorité moyenne rentrent dans le tight mode et seront donc chargées en parallèle des scripts prioritaires même si ces ressources moyennes ne sont pas chargées au même moment, il y a un effet de décalage qui se produit mais les images en priorité basse patientent.
Robin montre que pour une même page, le tight mode fonctionne très différemment sur Safari. Sous Safari, le tight mode permet aussi de charger des éléments à priorité basse mais les temps de traitement explosent : de 2,8 à 4,19 secondes pour les images PNG alors que sous Chrome, nous sommes à 148-161 ms !
Bref, le tight mode de Chrome est plus performant et intègre mieux les éléments de priorité basse et évite un temps supplémentaire de chargement. Safari est donc intrinsèquement plus lent à cause de son tight mode.
Une question de fetchpriority
Au lieu de laisser faire le navigateur, pourquoi ne pas forcer la priorité ? C’est ce que permet fetchpriority. Cependant, attention, vous pouvez attribuer des priorités de type high, low mais pas highest ou lowest. Et finalement, le navigateur aura le dernier mot. Et là encore, tout dépend du navigateur. Chrome permet un fetchpriority=high sur les images, les JavaScript différés et asynchrones, les JavaScript dans le haut du <body>. Safari se limite aux images. Bref, le comportement ne sera donc pas identique selon le navigateur ! Vous pouvez aussi attribuer low à votre fetchpriority sur des images, du JavaScript, le préchargement de polices. Sur Safari, ce n’est pas clair.
Firefox supporte le fetchpriority depuis octobre 2024.
Mais les anomalies ne s’arrêtent pas là. Est-ce que les priorités imposées par le fetchpriority sont strictement appliquées ? Oui et non d’après Robin. Il donne plusieurs exemples, citons :
- une police en high sera traitée en priorité haute par les 3 navigateurs
- une police en low sera bien en low dans Chrome et Safari mais en lowest dans Firefox.
Sans fetchpriority, l’assignation des priorités par les navigateurs est bizarre :
- une police préchargée sera en high sur Chrome et en moyenne pour Safari et Firefox
- une police « standard » pourra être en priorité très haute sur Chrome, en moyenne sur Safari et en basse sur Firefox
Bref, rien n'est simple dans le monde du web et on comprend mieux pourquoi les pages web prennent parfois autant de temps à se charger.