Web frontend · L2 · Section 4/6
Performance Web
Progression
#Performance Web
La règle qui précède toutes les autres : mesurez avant d'optimiser. Les Core Web Vitals donnent le vocabulaire commun entre équipes, et chaque métrique pointe un remède différent :
- LCP (Largest Contentful Paint, seuil 2.5 s) : le plus grand élément visible s'affiche. C'est la métrique du chargement perçu ; ses coupables sont les images d'en-tête non optimisées, les polices bloquantes et les serveurs lents.
- INP (Interaction to Next Paint, seuil 200 ms) : la réactivité à l'interaction a remplacé FID en mars 2024. Son coupable est le thread principal occupé, donc le JavaScript qui s'exécute longuement.
- CLS (Cumulative Layout Shift, seuil 0.1) : la stabilité visuelle. Ses coupables sont les images sans dimensions, les contenus injectés au-dessus de la ligne de flottaison et les bannières qui repoussent le contenu.
Méthode de mesure : une ligne de base en laboratoire (Lighthouse, onglet Performance avec throttling CPU 4x et réseau 4G) pour diagnostiquer, et du terrain (RUM, CrUX) car vos utilisateurs n'ont ni votre machine ni votre réseau.
#Le chemin de chargement, étape par étape
Comprendre d'où viennent les secondes : le navigateur parse, télécharge, exécute, puis affiche.
Deux corollaires immédiats : le CSS est prioritaire mais doit être court (extraire le CSS critique, charger le reste en media="print" togglé ou via rel="preload"), et le JS déferre (defer ou type="module") pour rendre avant d'exécuter.
#CDN et cache : le trajet d'une requête
Le HTML reste frais (courte durée ou revalidation), les assets fingerprintés (app-a3f9.js) profitent d'un max-age=31536000, immutable : chaque déploiement change le nom, donc le cache se réinvalide tout seul, sans purge.
#Feuille de route (du labo au terrain)
#Techniques qui rapportent, dans l'ordre
Images (premier levier LCP) : servez AVIF/WebP avec repli JPEG via <picture>, dimensionnez avec srcset/sizes, et réservez la place avec width/height (anti-CLS). L'image LCP se précharge :
1<link rel="preload" as="image" href="/hero.avif"2 fetchpriority="high" />3<img src="/hero.avif" width="1200" height="630" alt="…"4 fetchpriority="high" decoding="async" />Les images hors écran prennent loading="lazy" ; ne l'appliquez pas à l'image LCP, vous la retarderiez.
Polices : font-display: swap évite le texte invisible pendant le téléchargement (FOIT), au prix d'un bref flash (FOUT) ; déclarez les polices critiques en preload, sous-settez les jeux de caractères, et le format WOFF2 couvre tout.
JavaScript (premier levier INP) : le JS non utilisé au premier rendu se découpe par route, s'importe dynamiquement (import()), et s'élimine carrément (dépendances oubliées, polyfills inutiles en 2026). Un « long task » de plus de 50 ms retarde une interaction ; visez des tâches courtes ou découpez un gros calcul avec scheduler.yield().
Réseau : preconnect (1 à 2 origines critiques maximum) pour raccourcir DNS+TCP+TLS, Brotli (br) côté serveur pour les textes, HTTP/2 ou 3 pour multiplexer.
Budget de performance : à quoi ressemble un contrat ?
Un budget transforme la perf en échec de CI plutôt qu'en intention. Exemple pour une fiche produit : JS initial ≤ 150 Ko gzip, CSS ≤ 30 Ko, LCP labo ≤ 2.5 s sous throttling 4G, aucune régression > 10 % entre deux runs. On l'applique via Lighthouse CI ou le bundle Size limit plugins du gestionnaire de paquets. Un budget non surveillé n'existe pas.
#Mini-labs (mesure avant/après, avec captures)
- Images : compilez la même photo en JPEG qualité 80, WebP et AVIF, comparez les tailles, puis servez-la en
srcset. Mesurez le LCP dans Lighthouse avec throttling 4G avant et après la substitution. - Polices : ajoutez
font-display: swapet unpreloadsur la police du titre LCP. Observez le changement de LCP dans le timeline Performance : le texte apparait plus tôt. - Préconnexion : ajoutez
<link rel="preconnect" href="https://cdn.example.com">. Dans le Network, la première requête d'asset perd les étapes DNS/TLS (comparez les colonnes de timing). - Découpage JS : isolez un module lourd (éditeur, carte) en
import()dynamique déclenché à l'interaction. Mesurez le JS initial dans la Coverage de la DevTools avant/après, et l'INP sur une interaction de la page d'accueil.
Chaque lab se rend avec trois chiffres : la métrique avant, la métrique après, et l'hypothèse validée ou invalidée.