# Core Web Vitals en 2026 : pourquoi on s'acharne encore à optimiser > Les réseaux sont rapides, les navigateurs sont puissants. Pourtant, on continue à traquer chaque milliseconde. Retour sur ce que les Core Web Vitals changent vraiment — et pourquoi le feu d'artifice Lighthouse n'est pas qu'un caprice. Date : 11/03/2026 Auteur : Aurélien N. Tags : Performance, Web, Core Web Vitals, Lighthouse --- Il y a un plaisir coupable que tout développeur front connaît : lancer un audit Lighthouse, voir les jauges monter une à une, et obtenir le feu d'artifice — quatre scores verts, confettis à l'écran, 100/100 partout. On sait que c'est un outil de mesure synthétique, pas une fin en soi. Mais avouons-le : c'est profondément satisfaisant. J'ai dû lancer cet audit une vingtaine de fois le soir où on a mis en prod le nouveau site, juste pour revoir les confettis. Ce petit moment de dopamine, c'est ce qui m'a poussé, il y a quelques mois, à passer plusieurs jours à optimiser notre nouveau site. Pas quelques heures un vendredi après-midi — plusieurs *jours*, à traquer des dizaines de millisecondes, à déplacer un `preload` d'une ligne, à mesurer l'impact d'une font en moins. Et en chemin, je me suis posé la question que tout le monde me pose quand j'en parle : **en 2026, avec la fibre partout et des navigateurs qui optimisent tout seuls, est-ce que ça sert encore à quelque chose ?** ## "Avec la 5G et les navigateurs modernes, on s'en fiche, non ?" C'est l'argument qu'on entend le plus souvent — y compris chez des développeurs expérimentés. Les connexions sont rapides, les appareils sont puissants, Chrome fait du prefetch intelligent. Pourquoi se fatiguer ? Je pensais un peu la même chose avant de plonger dans les métriques réelles du terrain. Sauf que la réalité est plus nuancée que ce qu'on vit depuis nos MacBook Pro branchés en fibre. ### Le réseau n'est pas le goulot d'étranglement principal La bande passante a explosé, c'est vrai. Mais la latence, elle, n'a pas suivi au même rythme. Un aller-retour serveur prend toujours entre 20 et 100 ms en conditions réelles — et chaque ressource bloquante en ajoute un. Un site qui enchaîne trois requêtes séquentielles avant d'afficher quoi que ce soit sera lent, même sur la fibre. Et puis il y a les cas qu'on oublie trop facilement depuis nos bureaux parisiens : le métro entre Châtelet et Gare du Nord (bonne chance avec votre 5G), la 4G saturée un samedi à Châtelet-les-Halles, les zones rurales, les téléphones Android à 150 € qui représentent encore la majorité du trafic mondial. Quand on teste exclusivement sur un iPhone 17 en Wi-Fi 6, on ne teste pas grand-chose. ### Les navigateurs optimisent, mais ne font pas de miracles Le lazy loading natif, le prefetch, les service workers — les navigateurs ont ajouté des outils puissants. Mais ils ne peuvent pas compenser un bundle JavaScript de 2 Mo qui bloque le thread principal pendant 800 ms. Le navigateur exécute ce qu'on lui donne. Si on lui donne du code lourd, il rame — poliment, mais il rame. J'ai récemment audité le site d'un client qui utilisait un framework CSS avec 340 Ko de styles non-utilisés, un widget de chat de 200 Ko, et un consent manager qui chargeait trois scripts tiers avant même d'afficher la première ligne de texte. Résultat : 4,2 secondes de LCP sur mobile. En 2026. ## Ce que mesurent vraiment les Core Web Vitals Google a simplifié ses métriques au fil des ans. En 2026, on se concentre sur trois indicateurs : - **LCP (Largest Contentful Paint)** — le temps avant que le contenu principal soit visible. Seuil : 2,5 secondes. C'est le plus intuitif : est-ce que l'utilisateur voit quelque chose rapidement ? - **INP (Interaction to Next Paint)** — la réactivité aux interactions utilisateur. Remplaçant du FID depuis mars 2024, c'est devenu la métrique la plus exigeante. Seuil : 200 ms. Chaque clic, chaque tap doit produire un retour visuel en moins de 200 millisecondes. - **CLS (Cumulative Layout Shift)** — la stabilité visuelle. Ces décalages de mise en page agaçants qui font cliquer au mauvais endroit parce qu'une pub ou une image s'est chargée entre-temps. Seuil : 0,1. Ce ne sont pas des métriques techniques abstraites. Elles mesurent l'expérience *ressentie* par l'utilisateur. Est-ce que la page s'affiche vite ? Est-ce qu'elle répond quand je clique ? Est-ce qu'elle bouge sous mes doigts ? Si la réponse est non à l'une de ces questions, l'utilisateur le sent — même s'il ne sait pas l'expliquer. ## Pourquoi on s'acharne — pour de vrai ### Le SEO, évidemment Autant être direct : les Core Web Vitals sont un signal de classement Google. Pas le seul, pas le plus important, mais un signal quand même — et un signal de départage. Sur des requêtes concurrentielles, à contenu équivalent, la page la plus rapide gagne. On a vu des gains mesurables de positionnement après optimisation sur des sites clients. Pas de +50 positions du jour au lendemain, mais des progressions régulières de quelques places sur des requêtes où justement tout se joue à la marge. ### La conversion, surtout Chaque 100 ms de temps de chargement en plus, c'est environ 1 % de conversion en moins. Ce n'est pas nous qui le disons — c'est documenté par Google, Akamai, Amazon, et à peu près tous les acteurs du e-commerce depuis dix ans. En 2026, les utilisateurs sont encore plus impatients qu'avant. Ils ne comparent pas votre site à "un site en 2015". Ils le comparent à l'app qu'ils viennent de quitter. ### Le signal de qualité C'est le bénéfice le moins évident mais le plus durable. Un site rapide, c'est un site bien construit. Optimiser les Web Vitals, c'est inévitablement nettoyer le code, réduire les dépendances inutiles, structurer l'ordre de chargement. Les gains vont au-delà de la performance : moins de dette technique, moins de bugs obscurs, une base de code plus maintenable. Chaque fois que j'ai travaillé sur les performances d'un projet, j'ai trouvé des problèmes qu'on n'avait pas vus autrement. ### L'accessibilité Un site performant est un site plus accessible. Les utilisateurs sur des appareils modestes ou des connexions lentes sont souvent les mêmes qui ont le plus besoin du service — l'administration, la santé, les services publics. Optimiser, c'est aussi une question d'inclusion. Ce n'est pas un argument marketing. C'est une responsabilité. ## Ce qu'on a fait concrètement sur notre site On a reconstruit notre site sur Astro — un framework qui génère du HTML statique par défaut et n'envoie du JavaScript que quand c'est strictement nécessaire. Voici le journal de bord de l'optimisation, avec les choix qui ont eu le plus d'impact. ### Zéro JavaScript par défaut C'est le principe fondamental d'Astro : chaque page est du HTML pur. Les composants interactifs — un curseur custom, une animation au scroll — sont des "îles" qui s'hydratent de manière ciblée. Le reste, c'est du HTML et du CSS. Pas de runtime React de 40 Ko pour afficher du texte. Résultat concret : notre INP est à zéro sur les pages de contenu. Pas de JavaScript = pas d'interaction bloquée = pas de jank. ### La stratégie des fonts — le détail qui change tout Les fonts sont un piège classique pour le LCP. Une font non chargée, c'est soit un texte invisible pendant une à deux secondes (FOIT — Flash of Invisible Text), soit un texte qui saute quand la font arrive enfin (FOUT — Flash of Unstyled Text). Dans les deux cas, l'utilisateur le voit, et le CLS en prend un coup. La solution classique, c'est de pointer vers Google Fonts avec un `` dans le ``. Ça marche, mais ça implique deux connexions DNS supplémentaires (`fonts.googleapis.com` puis `fonts.gstatic.com`), un aller-retour pour récupérer le CSS, puis un autre pour chaque fichier de font. Sur une connexion moyenne, on perd facilement 200 à 400 ms rien qu'en réseau. Sans compter les questions de RGPD — chaque requête vers Google Fonts envoie l'IP de vos visiteurs chez Google. #### De fontless à la Fonts API native d'Astro 6 On a d'abord utilisé [fontless](https://github.com/herber/fontless), un plugin Vite qui télécharge les fonts Google au build et génère des `@font-face` optimisés avec fallbacks métriques via [fontaine](https://github.com/unjs/fontaine). L'idée est excellente — self-hosting automatique, zéro requête externe, polices système ajustées pour minimiser le CLS. En pratique, on s'est heurté à un problème structurel : fontless repose sur le hook Vite `transformIndexHtml` pour injecter les `` dans le HTML. Or Astro génère son propre HTML — ce hook n'est jamais appelé pendant le build statique. Résultat : malgré `preload: true` dans la config, aucun preload n'était injecté. On avait aussi un micro-plugin Vite pour forcer `font-display: optional` sur Newsreader, qui fonctionnait de manière intermittente selon le mode d'inlining CSS. Ce n'est pas un bug de fontless — c'est une incompatibilité architecturale entre les plugins Vite pensés pour les SPA et le modèle MPA d'Astro. Le même problème est documenté pour [SvelteKit](https://github.com/unjs/fontaine/issues/558) et [React Router](https://github.com/unjs/fontaine/issues/545). Avec Astro 6.0, le framework embarque une [Fonts API native](https://docs.astro.build/en/guides/fonts/) qui fait exactement ce que fontless faisait, mais intégrée au pipeline de build : ```javascript fonts: [ , , , ], }); ``` Chaque font est ensuite chargée dans le `` du layout via le composant `` : ```astro --- --- ``` Le résultat est propre : les `@font-face` sont injectés en `` inline dans le `` (découverte instantanée par le navigateur), les fallbacks métriques sont générés automatiquement (`ascent-override`, `descent-override`, `size-adjust`), et les fonts sont self-hosted sous `/_astro/fonts/` avec des headers de cache immutables. Plus besoin de plugin Vite custom, plus de hack `transformIndexHtml`, plus de duplication de `@font-face` à travers les chunks CSS. Et dans le CSS, on référence les fonts via des variables : `font-family: var(--font-dm-mono)` au lieu de `font-family: 'DM Mono', monospace`. ### Le JavaScript qui sait attendre Les animations décoratives — la texture de fond qui suit la souris, le curseur custom — ne sont pas critiques. On les diffère avec `requestIdleCallback` : ```javascript if ('requestIdleCallback' in window) { requestIdleCallback(initTextureMouse, ); } else ``` Le navigateur lance ces scripts quand il n'a rien de mieux à faire. En pratique, ça repousse l'exécution de quelques centaines de millisecondes — le temps que le contenu soit affiché et interactif. L'utilisateur ne remarque rien, mais le INP s'en porte beaucoup mieux. On va même plus loin : ces animations ne tournent que sur Chromium desktop. Sur Safari (où elles consomment plus de GPU) et sur mobile (où elles n'apportent rien sur écran tactile), on les désactive purement et simplement. Pas de demi-mesure. ### Prefetch au viewport Une ligne dans la config Astro, un gros impact sur la navigation : ```javascript prefetch: , ``` Tous les liens visibles à l'écran sont préchargés en arrière-plan. Quand l'utilisateur clique, la page est déjà en cache. La navigation interne est quasi instantanée — on mesure des temps de transition sous les 100 ms. C'est le genre d'optimisation invisible qui donne l'impression que le site est "nerveux". ### Les passive listeners et le requestAnimationFrame Un détail d'implémentation qui compte plus qu'on ne croit : chaque `scroll` listener du site est déclaré en ``. Ça indique au navigateur qu'on ne va pas appeler `preventDefault()`, ce qui lui permet d'optimiser le défilement sans attendre notre callback. Combiné avec un throttle par `requestAnimationFrame`, on obtient des animations au scroll (parallax, révélation progressive) à 60 fps sans bloquer le thread principal : ```javascript window.addEventListener('scroll', () => , ); ``` C'est le genre de pattern qu'on ne voit pas dans les tutos mais qui fait la différence entre un score Lighthouse à 95 et un score à 100. ### IntersectionObserver partout Plutôt que de calculer les positions des éléments à chaque scroll (bonjour le layout thrashing), on utilise `IntersectionObserver` pour déclencher les animations d'entrée : ```javascript const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) }); }, ); ``` Le `unobserve` après déclenchement est important : une fois l'élément révélé, on arrête de l'observer. Moins d'observers actifs = moins de travail pour le navigateur. ### HTML compressé, CSS scopé Deux lignes dans la config, zéro effort, quelques Ko en moins sur chaque page : ```javascript compressHTML: true, scopedStyleStrategy: 'class', ``` Le `compressHTML` supprime les espaces inutiles du HTML généré. Le `scopedStyleStrategy: 'class'` utilise des classes CSS pour le scoping des styles Astro au lieu de sélecteurs `:where()` — plus prévisible et marginalement plus performant. ## Les résultats Après tout ça : LCP sous la seconde, INP à zéro, CLS à zéro. Quatre fois 100 dans Lighthouse. Les confettis. Mais au-delà des chiffres, c'est l'expérience de navigation qui change. Le site *répond*. Les pages apparaissent. Les animations suivent le scroll sans accrocher. On ne peut pas le mesurer dans un rapport, mais on le sent. ## Le mot de la fin Optimiser les Core Web Vitals en 2026, ce n'est pas de l'obstination de développeur perfectionniste. C'est un investissement mesurable — en SEO, en conversion, en qualité technique. C'est aussi, pour être honnête, un exercice d'ingénierie qui force à comprendre comment fonctionne le navigateur en profondeur. On en ressort meilleur développeur. Les réseaux sont plus rapides, oui. Les navigateurs sont meilleurs, oui. Mais les attentes des utilisateurs ont augmenté encore plus vite. La barre monte. Et ceux qui la franchissent ont un avantage concret sur ceux qui se contentent de "ça charge, c'est bon". On préfère voir les feux d'artifice.