Skills/web-vitals-performance/SKILL.md

4.7 KiB

name description
web-vitals-performance Optimize real-world web performance according to Google Core Web Vitals (INP <= 200ms, LCP <= 2.5s, CLS <= 0.1). Enforces main thread budgets, scheduler.yield() task chunking, AVIF media pipelines, font metric overrides, and third-party script isolation.

Web Vitals & Real-World Performance Engineering

Ce skill garantit que les interfaces atteignent les seuils d'excellence des Core Web Vitals officiels (LCP ≤ 2.5s, INP ≤ 200ms, CLS ≤ 0.1) mesurés sur le terrain (Google Chrome User Experience Report - CrUX).


🎯 Déclencheurs d'Activation

Activez ce skill dès que :

  1. Vous chargez des médias lourds (images d'en-tête, bannières, galeries, vidéos).
  2. Vous intégrez des polices typographiques web (Google Fonts, polices locales).
  3. Vous développez des interactions utilisateur riches susceptibles de bloquer le thread principal (recherche instantanée, filtrage de tableau de données, calculs lourds côté client).
  4. Vous auditez ou optimisez les scores de performance d'une application avant son déploiement.

⚡ 1. Optimisation de l'INP (Interaction to Next Paint ≤ 200ms)

L'INP a définitivement remplacé le FID. Il mesure le délai entre une action utilisateur (clic, frappe, tap) et le moment exact où le navigateur affiche la prochaine image.

Règle d'Or : Budget du Thread Principal < 50ms

Toute tâche JS dépassant 50ms est une « Long Task » qui dégrade l'INP.

Découpage des Tâches Longues avec scheduler.yield()

// Utilitaire moderne pour rendre la main au navigateur pendant un traitement lourd
async function yieldToMain() {
  if ('scheduler' in window && 'yield' in (window as any).scheduler) {
    await (window as any).scheduler.yield();
  } else {
    // Fallback standard
    await new Promise((resolve) => setTimeout(resolve, 0));
  }
}

export async function processLargeDataset(items: Array<any>) {
  for (let i = 0; i < items.length; i++) {
    // Traitement de l'élément
    computeHeavyItem(items[i]);

    // Toutes les 50 itérations, on cède le contrôle au thread principal pour afficher les clics/peintures
    if (i % 50 === 0) {
      await yieldToMain();
    }
  }
}

🚀 2. Optimisation du LCP (Largest Contentful Paint ≤ 2.5s)

L'élément LCP (souvent l'image du Hero ou le titre H1 principal) doit être peint immédiatement :

  1. fetchpriority="high" Obligatoire sur l'image LCP :
    <img
      src="/images/hero.avif"
      alt="Tableau de bord de design"
      fetchpriority="high"
      loading="eager"
      decoding="async"
      width="1280"
      height="720"
    />
    
  2. Préchargement des Polices Critiques :
    <link
      rel="preload"
      href="/fonts/geist-sans.woff2"
      as="font"
      type="font/woff2"
      crossorigin="anonymous"
    />
    
  3. Format AVIF Prioritaire : Toujours servir l'AVIF en premier (gain de 20 à 35% de bande passante par rapport au WebP).

📐 3. Élimination Totale du CLS (Cumulative Layout Shift ≤ 0.1)

Le décalage de mise en page survient lorsque des éléments changent de position pendant le chargement.

Solutions Anti-CLS :

  1. Ratio d'aspect explicite : Tout conteneur d'image ou vidéo doit avoir une propriété CSS aspect-ratio ou des attributs width et height.
  2. Espace réservé pour la typographie : Utilisez @font-face avec des métriques de substitution pour éviter le saut entre police système et police web :
    @font-face {
      font-family: 'Geist-Fallback';
      src: local('Arial');
      ascent-override: 92%;
      descent-override: 24%;
      size-adjust: 102%;
    }
    
  3. Squelettes de chargement (Skeletons) : Réservez précisément la hauteur des blocs de contenu asynchrones.

📦 4. Gestion des Scripts Tiers (Analytics & Trackers)

Ne jamais insérer de balise <script src="..."> synchrone dans le <head> pour un outil d'analyse :

  • Utilisez strategy="lazyOnload" ou strategy="worker" (via Partytown pour déporter l'exécution dans un Web Worker).
  • Isolez les iframes et widgets d'assistance avec l'attribut loading="lazy".

📋 Checklist de Conformité Web Vitals

  • L'image principale LCP possède fetchpriority="high" et loading="eager".
  • Aucun média ne manque de dimensions ou d'attribut CSS aspect-ratio.
  • Les polices web utilisent font-display: swap et sont préchargées en WOFF2 local.
  • Les écouteurs d'événements lourds (scroll, input, resize) sont découpés via scheduler.yield() ou temporisés (debounced).
  • Le score CLS en navigation simulée est inférieur à 0.05.
  • Les images sont servies au format AVIF avec fallback WebP.