Qualité Frontend
Barre de qualité pour toute interface web utilisateur. Exigences strictes (a11y, perf, mobile-first), pas de préférences stylistiques. Les revues détectent les bugs qui comptent pour les vrais utilisateurs — pages lentes, navigation au clavier cassée, mises en page qui se déplacent pendant le chargement.
Routage du modèle
Utiliser la préférence frontend de l'opérateur lorsqu'un modèle doit critiquer ou réécrire l'interface utilisateur, l'expérience utilisateur, la hiérarchie visuelle, le texte d'accessibilité ou les détails d'interaction :
source "$WALTER_OS_HOME/scripts/walter/lib/model-router.sh"
frontend_model=""
walter_model_resolve frontend frontend_model
La préférence par défaut est Claude. L'opérateur peut rediriger l'alias vers une autre route LiteLLM dans ~/.config/walter-os/overlay/personal.env.
Cette compétence se déclenche automatiquement sur les diffs touchant le frontend. Pour une page d'accueil construite de zéro, utilisez landing-page-fast (qui inclut ces règles mais fournit un échafaudage).
Pourquoi cela est important spécifiquement pour cet opérateur
- [Projet A] les utilisateurs sont des fournisseurs PME argentins — beaucoup sur téléphone, souvent en 3G/4G avec connexion intermittente. Site lent = utilisateurs partent. WCAG est important car certains utilisateurs ont une faible culture numérique + une vision altérée.
- [Projet B] les utilisateurs incluent des patients handicapés. WCAG n'est pas "sympa à avoir" — c'est une exigence d'utilisabilité.
- Documentation [Société] est lue par des développeurs experts qui quittent instantanément un site lent ou avec un clavier cassé.
Accessibilité (WCAG 2.2 AA — obligatoire)
Clavier
- Chaque élément interactif atteignable par Tab. Boutons, liens, champs de formulaire, contrôles personnalisés. Effectuez une navigation manuelle avec Tab ; si un contrôle est sauté, BLOCKER.
- Focus visible. Le contour
:focus-visibledoit être évident. Ne mettez pasoutline: nonesans alternative. - Ordre de tabulation logique. L'ordre de lecture correspond à l'ordre du DOM ; évitez les valeurs
tabindex>0 (elles cassent le flux naturel). - Lien d'évitement. Le premier élément focalisable sur chaque page est "Aller au contenu principal".
- Échap ferme les modales. Piégez le focus à l'intérieur de la modale jusqu'à sa fermeture.
HTML sémantique
<button>pour les actions,<a>pour la navigation. Jamais<div onClick>pour l'un ou l'autre.- Hiérarchie des titres : un
<h1>par page ;<h2>...<h6>ne sautent pas de niveaux. - Repères :
<header>,<nav>,<main>,<footer>. Rôles ARIA seulement quand aucun élément sémantique ne convient. - Les listes sont
<ul>/<ol>. Ne simulez pas de listes avec<div>. - Les contrôles de formulaire ont
<label>. L'attributforcorrespond à l'id.
Couleur et contraste
- Contraste minimum WCAG AA : 4,5:1 pour le texte courant, 3:1 pour les grands textes (18pt+ ou 14pt+ en gras), 3:1 pour les composants d'interface et les graphiques.
- La couleur n'est pas le seul indicateur : les états d'erreur montrent une icône + du texte + de la couleur, pas seulement une bordure rouge.
- Testé avec simulation de daltonisme. Utilisez Stark, axe DevTools ou les simulateurs de vision des couleurs des outils de développement du navigateur.
Formulaires
- Chaque champ a un label visible. Le placeholder N'EST PAS un label.
- Les messages d'erreur sont associés par programme via
aria-describedby. - Champs obligatoires marqués. Visuellement (
*ou "obligatoire") ET par programme (aria-required="true"ourequired). - Les erreurs de validation ne disparaissent pas au focus. Persistent jusqu'à correction ou rejet.
- États de succès confirmés. Après la soumission, les utilisateurs de lecteurs d'écran savent que cela a fonctionné.
Images et médias
- Attribut
altsur chaque<img>. Vide (alt="") pour les images décoratives ; descriptif pour le contenu. Images générées par IA : décrivez ce qui est réellement dans l'image, pas le prompt. - Sous-titres/transcriptions pour les vidéos/audios.
- Pas d'autoplay avec son.
- Animations respectent
prefers-reduced-motion:@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
Outillage
@axe-core/reacten mode dev — consigne les problèmes d'accessibilité dans la console.eslint-plugin-jsx-a11y— détecte au moment de la construction.- Test manuel avec lecteur d'écran avant le lancement : VoiceOver (Mac), NVDA (Windows), TalkBack (Android).
- Score d'accessibilité Lighthouse ≥ 95 dans l'intégration continue.
Performance — Core Web Vitals
Les 3 métriques sur lesquelles Google classe. Passez TOUTES LES TROIS pour être "Bon" :
LCP (Largest Contentful Paint) — vitesse de chargement
Objectif : < 2,5s sur 3G. Dans le monde réel pour [Projet A], c'est plus agressif car les réseaux mobiles argentins sont plus lents que la médiane.
Comment faire :
- Précharger l'image LCP :
<link rel="preload" as="image" href="...">. - Pas de ressources bloquant le rendu : différer le JS non critique, intégrer le CSS critique en ligne.
- Polices auto-hébergées avec
font-display: swapou utiliser une pile de polices système. - CDN pour les actifs statiques : Vercel, Cloudflare R2, Bunny.net.
- HTTP/2 ou HTTP/3 : Vercel/Cloudflare par défaut.
- Compresser les images : WebP/AVIF, dimensionnées pour la fenêtre d'affichage.
- Optimiser l'image hero spécifiquement : c'est presque toujours LCP.
INP (Interaction to Next Paint) — réactivité
Objectif : < 200ms p75. A remplacé FID en 2024.
Comment faire :
- Pas de longues tâches > 50ms sur le thread principal pendant l'interaction.
- Différer l'hydratation (îlots Astro, streaming Next.js, qwik).
- Web Workers pour les calculs lourds.
- Debounce/throttle les gestionnaires d'entrée.
- Éviter
dangerouslySetInnerHTMLavec de grandes chaînes — le parsing bloque. useMemo/memouniquement là où mesuré, pas de manière préventive.
CLS (Cumulative Layout Shift) — stabilité visuelle
Objectif : < 0,1.
Comment faire :
- Les balises d'image et de vidéo ont
width+height(le navigateur réserve l'espace). - Réserver de l'espace pour les pubs/intégrations avec une hauteur minimale.
- Ne pas insérer de contenu au-dessus du contenu existant : les bannières de notification vont sous la ligne de flottaison ou poussent vers le bas via transform, pas en insérant dans le DOM au-dessus.
- Polices web : utiliser
font-display: swap+size-adjustpour correspondre aux métriques, OUfont-display: optionalsi possible. - Écrans squelette dimensionnés pour correspondre au contenu réel.
Taille du bundle
- Budget JS initial : < 150Ko gzippé pour les pages d'atterrissage, < 250Ko pour les coques d'application.
- Code-splitting par route (Next.js, Astro, SvelteKit le font par défaut).
- Importations dynamiques pour les dépendances lourdes non critiques (graphiques, éditeurs).
- Auditer les dépendances :
bundle-analyzerounext-bundle-analyzer. Supprimez la bibliothèque UI de 10 Mo dont vous avez importé un seul composant. - Tree-shaking fonctionnel : importer uniquement ce dont vous avez besoin (
import { thing } from 'lib'pasimport lib from 'lib').
Modèles de chargement
- Preconnect aux origines requises :
<link rel="preconnect" href="...">. - Prefetch des pages probables suivantes au survol/focus (Next.js le fait).
- Chargement paresseux des images sous la ligne de flottaison :
loading="lazy". - Chargement paresseux des iframes :
loading="lazy". - Service Worker pour un mode hors-ligne (là où cela a du sens — [Projet A] en bénéficie, les pages marketing non).
États — chaque composant gère les cinq
Pour toute interface pilotée par des données, BLOCKER si un état n'est pas géré :
- Chargement — squelette ou spinner. PAS d'écran blanc. PAS de changement de mise en page.
- Vide — état de première fois, sans données. Avec CTA pour remplir.
- Erreur — message clair, bouton de réessai, pas de stack trace pour l'utilisateur. Journalisé dans Sentry.
- Partiel / obsolète — lorsque les données proviennent du cache ou d'une récupération partielle.
- Succès — le chemin heureux.
Exemple pour une liste :
if (isLoading) return <ListSkeleton />
if (error) return <ErrorState onRetry={refetch} />
if (data.length === 0) return <EmptyState cta={...} />
return <List items={data} />
Si votre composant ne montre que l'état de succès dans le diff, demandez : où vivent les 4 autres ?
Mobile-first
- Concevoir d'abord pour 360px de large, puis adapter vers le haut.
- Cibles tactiles ≥ 44×44px (Apple HIG) ou 48×48px (Material).
- Pas d'interactions survol-only : tout ce qui est disponible au survol a aussi un chemin par focus/toucher.
- Tester sur un vrai appareil ou chrome devtools limité : réseau 3G, ralentissement CPU 4×.
- Les formulaires fonctionnent sans zoom :
font-size: 16px+sur les champs (sinon iOS zoome au focus).
Référence d'outillage
CI / avant fusion :
- Lighthouse CI avec des budgets par métrique.
@axe-core/cliou sous-ensemble d'accessibilité Lighthouse.bundlewatchpour faire échouer les PR qui augmentent le bundle au-delà du budget.- Régression visuelle : Chromatic (Storybook), Percy, ou captures d'écran Playwright vérifiées.
Local :
- Chrome DevTools panneaux Performance + Lighthouse.
unlighthousepour un audit complet du site.@unjs/check-vitalspour un contrôle ponctuel des Web Vitals.
Format de sortie
**[BLOCKING|WARN|NIT] [FE-N] <une ligne>**
Où : `chemin/vers/Component.tsx:42-58`
Catégorie : <a11y | perf | states | mobile | semantic>
Impact : <quel utilisateur / scénario / métrique>
Correctif : <changement spécifique, code si cela tient>
Vérification : <comment confirmer — exécution Lighthouse / test manuel / etc.>
Sévérité :
- BLOCKING : violation WCAG AA, flux principal cassé, Web Vitals dans la zone "Médiocre". Doit être corrigé.
- WARN : écart par rapport aux meilleures pratiques, régression de performance non encore visible par l'utilisateur.
- NIT : opportunité d'amélioration (bundle plus petit, meilleur squelette).
Règles strictes
- Pas de
<div onClick>pour les boutons. Toujours. - Pas d'images sans
alt. Toujours. - Pas de changement de mise en page dû au contenu réel. Réservez toujours l'espace.
- Pas d'autoplay avec son. Toujours.
prefers-reduced-motionrespectée. Toujours.
Ce que cette compétence NE COUVRE PAS
- Backend (utilisez
web-security-baseline). - Schéma / requêtes de base de données (utilisez
data-migration-safety). - Identité de marque / design visuel (utilisez
brand-creation). - Construction d'une nouvelle page d'accueil (utilisez
landing-page-fastqui fournit un échafaudage).
Références
- Référence rapide WCAG 2.2
- Documentation web.dev Core Web Vitals
- Parcours d'apprentissage des performances web.dev
- Inclusive Components par Heydon Pickering
- Checklist du projet A11y