13.1 — Mesurer avant d'optimiser
🎯 Objectif : ne jamais optimiser sans mesure préalable. Apprendre les 3 indicateurs qui comptent (LCP, INP, CLS), les outils pour les obtenir, et la différence entre labo (synthétique) et terrain (RUM).
À l'issue de cet axe, tu sauras :
- Comprendre LCP, INP et CLS — les Core Web Vitals 2026
- Lire un rapport Lighthouse sans s'arrêter au score global
- Utiliser Chrome DevTools Performance pour profiler une page
- Mettre en place du Real User Monitoring (RUM) avec web-vitals.js
- Choisir entre mesures labo et terrain selon le contexte
Confirmé
La règle d’or : mesurer avant d’optimiser
Section intitulée « La règle d’or : mesurer avant d’optimiser »« Premature optimization is the root of all evil. » — Donald Knuth
Optimiser sans mesurer, c’est :
- Perdre du temps sur ce qui n’est pas le bottleneck.
- Casser des choses qui marchent (un cache mal placé crée des bugs subtils).
- Ne pas savoir si ça a marché — pas de mesure « avant », pas de comparaison.
La séquence saine est toujours la même :
- Mesurer → identifier la métrique qui pose problème.
- Hypothèse → quelle cause probable ?
- Modifier une seule chose à la fois.
- Re-mesurer → comparer avant/après.
- Conserver ou annuler.
Les 3 Core Web Vitals 2026
Section intitulée « Les 3 Core Web Vitals 2026 »Google Core Web Vitals : 3 métriques user-centric standardisées qui pèsent dans le SEO et reflètent la perception réelle de la performance.
| Vital | Mesure | Bon | À améliorer | Mauvais |
|---|---|---|---|---|
| LCP (Largest Contentful Paint) | Temps avant le plus gros élément visible | ≤ 2,5 s | ≤ 4,0 s | > 4,0 s |
| INP (Interaction to Next Paint) | Latence ressentie sur les interactions | ≤ 200 ms | ≤ 500 ms | > 500 ms |
| CLS (Cumulative Layout Shift) | Décalages de mise en page imprévus | ≤ 0,1 | ≤ 0,25 | > 0,25 |
INP a remplacé FID en mars 2024. INP regarde toutes les interactions (clic, tap, clavier), pas seulement la première. Beaucoup plus exigeant en pratique.
timeline
title Cycle de vie d'une page
Chargement : LCP — Largest Contentful Paint
Interactivité : INP — Interaction to Next Paint
Stabilité : CLS — Cumulative Layout Shift LCP — la perception du chargement
Section intitulée « LCP — la perception du chargement »Le LCP mesure quand l’élément le plus gros visible (image hero, gros bloc de texte, vidéo) finit de s’afficher. C’est ce qui te fait dire « la page a chargé ».
Bottlenecks classiques :
| Cause | Symptôme | Piste |
|---|---|---|
| Image hero trop lourde | LCP > 4 s | srcset, AVIF/WebP, fetchpriority="high" |
| Police bloquante | Texte invisible 2-3 s | font-display: swap, preload |
| JS qui retarde le rendu | LCP retardé | défer le JS non critique |
| Serveur lent (TTFB > 600 ms) | LCP plafonne | cache, edge, DB |
| Render-blocking CSS | First Paint tard | inliner le CSS critique |
INP — la perception de la fluidité
Section intitulée « INP — la perception de la fluidité »INP mesure la latence d’interaction. Quand tu cliques sur un bouton, combien de temps avant que le prochain frame visible reflète l’action ?
Bottlenecks classiques :
- Long tasks sur le main thread (> 50 ms) qui bloquent le clic.
- Re-rendus React/Vue trop coûteux sur chaque keystroke.
- Hydratation lourde d’une page SSR au premier clic.
- Listeners non passifs sur scroll/touch.
CLS — la stabilité visuelle
Section intitulée « CLS — la stabilité visuelle »CLS additionne tous les décalages inattendus au cours de la session. Une bannière qui pousse le contenu vers le bas après chargement = utilisateur qui clique sur la mauvaise chose.
Bottlenecks classiques :
| Cause | Correctif |
|---|---|
Image sans width / height | Toujours définir les dimensions ou un aspect-ratio |
| Police qui change la métrique au swap | size-adjust, ascent-override (font fallback métriquement compatible) |
| Bannière cookies qui pousse | position: fixed ou réserver l’espace |
| Pub injectée dynamiquement | Conteneur avec hauteur fixe |
Animation top/left au lieu de transform | transform ne déclenche pas de layout |
Les autres métriques utiles (mais pas Core)
Section intitulée « Les autres métriques utiles (mais pas Core) »Selon le contexte, regarde aussi :
| Métrique | Sens | Bon à savoir |
|---|---|---|
| TTFB (Time To First Byte) | Latence serveur | LCP plafonne au TTFB. < 600 ms idéal. |
| FCP (First Contentful Paint) | Premier pixel rendu | Bon proxy pour « ça commence à s’afficher ». |
| TBT (Total Blocking Time) | Somme des long tasks pendant le chargement | Proxy labo de l’INP futur. |
| Speed Index | Vitesse perçue d’apparition | Bon pour comparer 2 versions. |
| Hydration Time | Combien de temps avant interactif | Pertinent SSR/Next.js/Astro. |
Outils — labo (synthétique) vs terrain (RUM)
Section intitulée « Outils — labo (synthétique) vs terrain (RUM) »Labo — Lighthouse, WebPageTest, DevTools
Section intitulée « Labo — Lighthouse, WebPageTest, DevTools »Tests synthétiques : exécutés depuis un environnement contrôlé (CPU bridé, réseau simulé). Reproductibles, rapides, idéaux en CI.
| Outil | Usage |
|---|---|
| Lighthouse (DevTools / CLI / CI) | Audit complet rapide, score perf + a11y + best practices + SEO |
| PageSpeed Insights | Lighthouse + données CrUX terrain agrégées par Google |
| WebPageTest | Multi-locations, multi-réseaux, waterfall détaillé |
| Chrome DevTools Performance | Profil détaillé : main thread, layers, paints |
Bundle Analyzer (webpack-bundle-analyzer, vite-bundle-visualizer, @next/bundle-analyzer) | Identifier les gros poids JS |
Terrain — Real User Monitoring (RUM)
Section intitulée « Terrain — Real User Monitoring (RUM) »Ce que vivent tes vrais utilisateurs, sur leurs vrais devices. Les meilleurs outils :
| Outil | Force |
|---|---|
| web-vitals.js | 3 KB, gratuit, capture LCP/INP/CLS et envoie à ton backend |
| Google CrUX | Données terrain agrégées par Chrome (gratuit, dispo via PSI / Search Console) |
| Vercel Analytics / Cloudflare Web Analytics | RUM clé en main, sans impact perf |
| Sentry Performance / Datadog RUM | Plus riches (sessions complètes, replays) |
| PostHog | OSS, RUM + product analytics |
Exemple minimal avec web-vitals :
import { onLCP, onINP, onCLS } from 'web-vitals';
function send(metric: { name: string; value: number; rating: string }) { navigator.sendBeacon('/rum', JSON.stringify(metric));}
onLCP(send);onINP(send);onCLS(send);navigator.sendBeacon est non-bloquant et survit au pagehide — parfait pour ne pas perdre les mesures à la fermeture de l’onglet.
Choisir : labo ou terrain ?
Section intitulée « Choisir : labo ou terrain ? »| Question | Labo | Terrain |
|---|---|---|
| « Cette PR a-t-elle régressé ? » | ✅ rapide, reproductible | ❌ trop lent à observer |
| « Quels users souffrent le plus ? » | ❌ univers fictif | ✅ segmentation device/réseau |
| « Quel est notre LCP p75 vrai ? » | ❌ approximation | ✅ valeur réelle |
| « Trouver une régression rare (1 % users) » | ❌ jamais reproduite | ✅ visible en agrégé |
Combinaison saine : Lighthouse en CI (régressions PR) + RUM en prod (réalité terrain).
Lire un rapport Lighthouse — ce qui compte vraiment
Section intitulée « Lire un rapport Lighthouse — ce qui compte vraiment »Hiérarchie des sections, par ordre d’importance pour la perf :
- Métriques — LCP, INP (proxy TBT), CLS, FCP, TTFB.
- Diagnostics — opportunités (combien gagnerait-on à faire X ?).
- Treemap des bundles JS et CSS (où est le poids ?).
- Trace (l’onglet Performance dans DevTools) pour creuser.
Les opportunités Lighthouse les plus actionnables :
- Eliminate render-blocking resources → CSS/JS chargés trop tôt.
- Properly size images → tu sers du 4000×3000 pour un slot de 800 px.
- Defer offscreen images →
loading="lazy". - Avoid enormous network payloads → bundle JS > 500 KB compressé.
- Reduce unused JavaScript → tree-shaking insuffisant, dépendances trop grosses.
- Avoid long main-thread tasks → script qui bloque > 50 ms.
Profiler avec Chrome DevTools Performance
Section intitulée « Profiler avec Chrome DevTools Performance »Workflow standard pour traquer un problème :
- Onglet Performance → bouton record (Ctrl+E).
- Reproduis le scénario lent (clic, scroll, navigation).
- Stop → DevTools t’affiche un flame chart.
- Cherche les barres rouges (long tasks) en haut.
- Clique dessus → tu vois la stack JavaScript responsable.
- Compare Total Blocking Time avant/après ton fix.
Mettre la perf en CI
Section intitulée « Mettre la perf en CI »Bloque les régressions à la PR avec Lighthouse CI :
on: [pull_request]jobs: lhci: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 24 } - run: npm ci && npm run build - run: npx --yes @lhci/cli@0.14.x autorun env: LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}Et un lighthouserc.json avec des budgets durs :
{ "ci": { "collect": { "url": ["http://localhost:3000/"], "numberOfRuns": 3 }, "assert": { "assertions": { "largest-contentful-paint": ["error", { "maxNumericValue": 2500 }], "cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }], "total-blocking-time": ["error", { "maxNumericValue": 200 }], "categories:performance": ["warn", { "minScore": 0.9 }] } } }}Une PR qui dépasse ces budgets ne mergera pas. C’est l’équivalent perf de tes tests unitaires.
Auto-évaluation
Section intitulée « Auto-évaluation »Pour aller plus loin
Section intitulée « Pour aller plus loin »- web.dev / vitals — web.dev/vitals — référence officielle Google
- web-vitals.js — github.com/GoogleChrome/web-vitals
- WebPageTest — webpagetest.org
- Lighthouse CI — github.com/GoogleChrome/lighthouse-ci
- Why is my page slow? — Tim Kadlec (méthodologie de diagnostic)
Suite : 13.2 — Optimisations frontend pour les leviers concrets côté navigateur.