125 lines
4.7 KiB
Markdown
125 lines
4.7 KiB
Markdown
---
|
|
name: web-vitals-performance
|
|
description: >-
|
|
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()`
|
|
```typescript
|
|
// 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 :
|
|
```html
|
|
<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** :
|
|
```html
|
|
<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 :
|
|
```css
|
|
@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.
|