Demandez à Claude Code de "rendre ça responsive" sans rien lui expliquer. Voici ce que
vous obtenez : des media queries desktop-first avec des max-width partout,
du text-align: justify qui ressemble à du fromage suisse sur iPhone SE, des
boutons de 32px de hauteur intappables avec un pouce, et aucun font-size: 16px
sur les inputs — donc zoom automatique iOS garanti. Ce n'est pas de l'incompétence, c'est
de l'absence de contexte. Claude code avec les règles CSS génériques qu'il connaît, pas
avec les règles spécifiques au mobile que vous avez en tête.
La solution : un fichier CLAUDE.md spécialisé. Pas le CLAUDE.md générique du projet, un fichier dédié au redesign mobile et au CSS design, avec les règles précises, les pièges à éviter, et les cibles à atteindre. Claude le lit au démarrage de la session et applique ces règles systématiquement.
Le problème : Claude sans contexte mobile
Claude Code est un outil généraliste. Il connaît le CSS, il connaît le responsive, mais il ne sait pas quelles sont vos priorités. Est-ce que le projet cible des iPhone SE à 375px ou des tablettes à 768px ? Est-ce que le Lighthouse Accessibility doit passer 90 ? Est-ce que le dark mode est obligatoire ? Est-ce que vous préférez BEM ou utility-first ?
Sans ces informations, Claude produit du CSS correct mais générique. Il va :
- Partir du desktop et descendre (
max-width) plutôt que l'inverse - Oublier
min-width: 0sur les flex items — résultat : débordements mystérieux - Laisser des inputs à 14px — zoom iOS sur chaque tap
- Mettre des
text-align: justifyparce que "ça fait propre" - Ignorer
prefers-reduced-motionetsafe-area-inset - Ne pas tester le dark mode
Chacun de ces problèmes se règle en 10 secondes une fois détecté. Le problème c'est qu'ils s'accumulent et qu'on les détecte après avoir livré.
Le concept CLAUDE.md spécialisé
Claude Code lit automatiquement les fichiers CLAUDE.md présents dans le projet
— à la racine, et dans les sous-dossiers si l'instruction est dans la config. C'est le
mécanisme officiel pour injecter du contexte persistant dans une session Claude Code, sans
avoir à le répéter à chaque prompt.
La plupart des projets ont un CLAUDE.md générique : architecture du projet, conventions de code, commandes de dev. L'idée ici est différente : créer des CLAUDE.md spécialisés pour des tâches précises. Un fichier dédié au redesign mobile contient exactement ce dont Claude a besoin pour cette tâche — et rien de superflu.
On peut l'appeler CLAUDE-MOBILE.md et le référencer depuis le CLAUDE.md
principal, ou simplement le coller temporairement à la racine sous le nom CLAUDE.md
le temps du chantier responsive. Claude Code supporte aussi le répertoire
.claude/ pour des fichiers de contexte supplémentaires — ils sont chargés
en plus du CLAUDE.md racine, pas à la place.
Ce que contient ce MD — et pourquoi chaque section
Le fichier est structuré en cinq sections. Chacune répond à un moment précis du travail.
Section 1 — Workflow d'audit. Avant d'écrire du CSS, il faut savoir où regarder. Cette section donne à Claude un ordre précis : d'abord la balise viewport, ensuite les font-sizes des inputs, ensuite l'overflow horizontal, ensuite les touch targets. C'est l'ordre qui minimise le temps passé à déboguer des problèmes causés par un oubli en amont. Elle inclut aussi les cibles Lighthouse et la checklist "mobile done" — ce qui évite à Claude de déclarer le travail terminé trop tôt.
Section 2 — Outils de test mobile. Les scripts Playwright pour prendre
des screenshots automatisés sur plusieurs profils de devices — iPhone SE, iPhone 14, Pixel 7,
iPad — sans quitter le terminal. Des variantes pour le dark mode et prefers-reduced-motion.
Les MCP servers (Puppeteer MCP, Playwright MCP) qui permettent à Claude Code d'interagir
directement avec un navigateur headless pendant la session. Et Lighthouse en CLI pour auditer
en JSON ou HTML sans ouvrir DevTools.
Section 3 — Règles CSS. La référence complète des règles mobiles avec du
code concret pour chacune. Pas de la doc générique : des snippets prêts à l'emploi avec les
cas limites déjà traités. Le piège du min-width: 0 sur les flex items, la
coexistence du toggle manuel avec prefers-color-scheme, les attributs HTML
inputmode qui complètent le CSS des formulaires — tout ce qui se perd quand
on travaille vite.
Section 4 — Conventions CSS génériques. Mobile ou pas, ces règles
s'appliquent à tout chantier CSS : custom properties pour le theming, BEM pour les
composants, focus-visible pour l'accessibilité clavier, propriétés modernes
(clamp(), gap, aspect-ratio, propriétés logiques),
et la règle sur !important. C'est ce qui évite que le CSS de la session
ressemble à un patch appliqué sur du code existant.
Section 5 — Checklist de test. Les devices à tester, les modes (paysage, dark, reduced motion, zoom texte), les cibles Lighthouse par métrique, et les bases du test lecteur d'écran. Claude s'en sert pour savoir quand la tâche est vraiment terminée, pas juste "ça passe sur mon émulateur Chrome 1440px".
Comment l'utiliser
Trois façons, de la plus simple à la plus propre :
Option 1 — Remplacement temporaire. Renommer ou sauvegarder le CLAUDE.md
existant, coller ce fichier à la racine sous le nom CLAUDE.md le temps du
chantier responsive. Restaurer l'original une fois terminé. Simple, sans configuration.
Option 2 — Référence depuis le CLAUDE.md existant. Ajouter une ligne dans le CLAUDE.md du projet :
## Contexte mobile
Pour tout travail sur le responsive et le CSS :
voir CLAUDE-MOBILE.md à la racine du projet.
Claude Code suit les références et lit le fichier pointé.
Option 3 — Répertoire .claude/. Placer le fichier dans
.claude/mobile-css.md. Claude Code charge automatiquement les fichiers
présents dans ce répertoire en complément du CLAUDE.md racine. Utile si vous avez
plusieurs contextes spécialisés (un pour le mobile, un pour les tests, un pour le
déploiement) et que vous ne voulez pas les fusionner.
Dans tous les cas, le fichier s'empile avec le contexte existant — il ne remplace pas les instructions déjà présentes.
Le fichier complet
Voici le contenu exact à copier. C'est le fichier brut, prêt à être collé.
# CLAUDE.md — Redesign Mobile & CSS Design
> Contexte spécialisé pour Claude Code. Coller ce fichier à la racine du projet pour guider le travail sur le responsive mobile et le design CSS.
---
## Section 1 : Workflow de redesign mobile
### Audit initial — par où commencer
Avant de toucher une seule ligne de CSS, faire un passage rapide dans cet ordre :
1. **Balise viewport** — présente ? `width=device-width, initial-scale=1` ? Pas de `user-scalable=no` ?
2. **font-size sur les inputs** — inspecter les champs `<input>`, `<textarea>`, `<select>`. Si < 16px : zoom iOS garanti.
3. **Overflow horizontal** — ouvrir Chrome DevTools en mode mobile, regarder si une scrollbar apparaît en bas. Traquer avec `* { outline: 1px solid red; }`.
4. **Touch targets** — tapper sur les boutons et liens de nav en mode émulation. Tout ce qui fait < 44px de hauteur est à corriger.
5. **Textes justifiés** — rechercher `text-align: justify` dans le CSS. Supprimer ou limiter au desktop uniquement.
### Lighthouse mobile — cibles
Lancer Lighthouse en mode "Mobile" (pas Desktop) dans DevTools :
| Métrique | Cible |
|----------|-------|
| Performance | ≥ 80 |
| Accessibility | ≥ 90 |
| Best Practices | ≥ 90 |
| SEO | ≥ 90 |
Les alertes à corriger en priorité : tap targets trop petits, contraste insuffisant, viewport manquant, inputs sans label.
### DevTools device emulation
- Tester avec les profils : **iPhone SE (375px)**, **iPhone 14 (390px)**, **Pixel 7 (412px)**, **iPad (768px)**
- Activer "Show media queries" pour voir les breakpoints actifs
- Tester en mode paysage (landscape)
- Simuler réseau "Slow 4G" pour détecter les problèmes de performance
### Test sur vrai device
L'émulation ne remplace pas le test réel. Points spécifiques à vérifier sur un vrai téléphone :
- Zoom automatique iOS sur les inputs (ne se voit qu'en vrai)
- Scroll momentum et zones de rebond
- Safe areas (encoche, barre de navigation)
- Clavier virtuel qui pousse le layout
### Checklist "mobile done"
- [ ] Aucun scroll horizontal non intentionnel
- [ ] Tous les éléments interactifs ≥ 44×44px
- [ ] Aucun input avec font-size < 16px
- [ ] Viewport meta tag correct
- [ ] Pas de `text-align: justify` sur mobile
- [ ] Corps de texte ≥ 16px, line-height ≥ 1.5
- [ ] Images avec `max-width: 100%`
- [ ] Dark mode fonctionne (si implémenté)
- [ ] Animations respectent `prefers-reduced-motion`
- [ ] Lighthouse Accessibility ≥ 90
---
## Section 2 : Outils de test mobile — screenshots, émulation, MCP
### Installation des dépendances de test
```bash
# Playwright (recommandé — multi-navigateur)
npm init -y
npm install playwright
npx playwright install chromium
# OU Puppeteer (Chromium uniquement)
npm install puppeteer
```
### Screenshots mobile automatisés
```javascript
// screenshot-mobile.mjs
import { chromium } from 'playwright';
const devices = [
{ name: 'iPhone SE', width: 375, height: 667, scale: 2 },
{ name: 'iPhone 14', width: 390, height: 844, scale: 3 },
{ name: 'Pixel 7', width: 412, height: 915, scale: 2.625 },
{ name: 'iPad', width: 768, height: 1024, scale: 2 },
];
const url = process.argv[2] || 'http://localhost:8000';
const browser = await chromium.launch();
for (const device of devices) {
const context = await browser.newContext({
viewport: { width: device.width, height: device.height },
deviceScaleFactor: device.scale,
isMobile: device.width < 768,
hasTouch: device.width < 768,
});
const page = await context.newPage();
await page.goto(url, { waitUntil: 'networkidle' });
await page.screenshot({
path: `screenshot-${device.name.toLowerCase().replace(/\s/g, '-')}.png`,
fullPage: true,
});
console.log(`✓ ${device.name} (${device.width}px)`);
await context.close();
}
await browser.close();
```
Usage :
```bash
node screenshot-mobile.mjs http://localhost:8000
# Génère : screenshot-iphone-se.png, screenshot-iphone-14.png, etc.
```
Claude Code peut lire ces screenshots pour vérifier visuellement le rendu.
### Dark mode et reduced motion screenshots
```javascript
// screenshot-modes.mjs — variantes dark mode et reduced motion
import { chromium } from 'playwright';
const url = process.argv[2] || 'http://localhost:8000';
const browser = await chromium.launch();
// Dark mode - iPhone 14
const darkCtx = await browser.newContext({
viewport: { width: 390, height: 844 },
deviceScaleFactor: 3,
isMobile: true,
hasTouch: true,
colorScheme: 'dark',
});
const darkPage = await darkCtx.newPage();
await darkPage.goto(url, { waitUntil: 'networkidle' });
await darkPage.screenshot({ path: 'screenshot-dark-mode.png', fullPage: true });
console.log('✓ Dark mode');
await darkCtx.close();
// Reduced motion - iPhone 14
const reducedCtx = await browser.newContext({
viewport: { width: 390, height: 844 },
deviceScaleFactor: 3,
isMobile: true,
hasTouch: true,
reducedMotion: 'reduce',
});
const reducedPage = await reducedCtx.newPage();
await reducedPage.goto(url, { waitUntil: 'networkidle' });
await reducedPage.screenshot({ path: 'screenshot-reduced-motion.png', fullPage: true });
console.log('✓ Reduced motion');
await reducedCtx.close();
await browser.close();
```
### MCP Servers utiles
**Puppeteer MCP** (`@modelcontextprotocol/server-puppeteer`) :
- Permet à Claude Code de naviguer sur un site, prendre des screenshots, inspecter le DOM
- Configuration dans `.claude/settings.json` :
```json
{
"mcpServers": {
"puppeteer": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-puppeteer"]
}
}
}
```
**Playwright MCP** (community `playwright-mcp`) :
- Même principe, multi-navigateur
- Utile pour tester le rendu sur différents moteurs (Chromium, Firefox, WebKit/Safari)
### Lighthouse en CLI
```bash
# Installation
npm install -g lighthouse
# Audit mobile
lighthouse http://localhost:8000 --preset=perf --form-factor=mobile --output=html --output-path=./lighthouse-mobile.html
# Audit mobile en JSON (parsable)
lighthouse http://localhost:8000 --form-factor=mobile --output=json --output-path=./lighthouse-mobile.json
```
Claude Code peut lire le rapport HTML pour identifier les problèmes.
### Debug avec Chrome DevTools Protocol
Playwright et Puppeteer exposent le CDP (Chrome DevTools Protocol), ce qui permet un accès programmatique à :
- **Network throttling** — simuler une connexion Slow 3G/4G pour détecter les goulots de chargement
- **CSS coverage** — identifier les règles CSS jamais appliquées (dead code)
- **Performance traces** — capturer une trace complète pour analyser le rendu frame par frame
---
## Section 3 : Règles CSS Mobile — référence complète
### Viewport meta tag
```html
<!-- ✅ Correct -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Si on utilise safe-area-inset -->
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<!-- ❌ Ne jamais faire : empêche le zoom pour les malvoyants -->
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, maximum-scale=1">
```
### Reset de base
```css
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
}
html, body {
overflow-x: hidden;
max-width: 100%;
}
img, video, svg {
max-width: 100%;
height: auto;
display: block;
}
```
### Alignement des textes
Règle simple : **gauche par défaut, centré uniquement pour les CTA, jamais justify sur mobile**.
```css
/* Base mobile */
h1, h2, h3, h4 {
text-align: left;
}
p, li {
text-align: left;
}
/* CTA : centré */
.cta-wrapper {
text-align: center;
}
/* Justify uniquement sur desktop avec césure */
@media (min-width: 768px) {
.prose p {
text-align: justify;
hyphens: auto;
-webkit-hyphens: auto;
}
}
```
### Touch targets — 44×44px minimum
```css
/* Boutons */
.btn {
min-height: 44px;
min-width: 44px;
padding: 12px 20px;
display: inline-flex;
align-items: center;
justify-content: center;
}
/* Liens de navigation */
nav a {
display: block;
min-height: 44px;
padding: 12px 16px;
line-height: 20px;
}
/* Icônes cliquables */
.icon-btn {
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
/* Zone de tap élargie sans changer l'apparence */
.small-icon {
position: relative;
width: 20px;
height: 20px;
}
.small-icon::after {
content: '';
position: absolute;
inset: -12px;
}
```
### Font-size — prévention zoom iOS et lisibilité
```css
/* ❌ Moins de 16px sur les inputs = zoom iOS automatique */
/* ✅ Minimum absolu sur les inputs */
input,
textarea,
select {
font-size: 16px;
}
/* Si taille différente souhaitée sur desktop */
@media (min-width: 768px) {
input,
textarea,
select {
font-size: 14px;
}
}
/* Corps de texte */
body {
font-size: 16px;
line-height: 1.6;
}
/* Titres fluides avec clamp() */
h1 { font-size: clamp(1.5rem, 5vw, 2.5rem); }
h2 { font-size: clamp(1.25rem, 4vw, 2rem); }
h3 { font-size: clamp(1.1rem, 3vw, 1.5rem); }
```
### Media queries — mobile-first uniquement
```css
/* ✅ Mobile-first : base = mobile, on ajoute pour les grands écrans */
.card {
display: block;
padding: 16px;
}
@media (min-width: 768px) {
.card {
display: flex;
padding: 24px;
}
}
@media (min-width: 1024px) {
.card {
padding: 32px;
}
}
/* ❌ Desktop-first : à éviter */
.card {
display: flex;
padding: 32px;
}
@media (max-width: 767px) {
.card {
display: block;
padding: 16px;
}
}
```
Breakpoints standards : `480px`, `768px`, `1024px`, `1280px`.
### Prévention overflow-x
```css
html, body {
overflow-x: hidden;
max-width: 100%;
}
/* Tableaux : scroll plutôt que casser le layout */
.table-wrapper {
overflow-x: auto;
}
table {
min-width: 600px;
width: 100%;
}
/* Debug : identifier l'élément qui déborde */
* { outline: 1px solid red; }
```
Attention : `overflow-x: hidden` sur `body` peut casser `position: sticky`. Si un sticky ne fonctionne plus, isoler `overflow-x: hidden` sur un wrapper dédié.
### Images et aspect-ratio
```css
img {
max-width: 100%;
height: auto;
display: block;
}
/* Ratio fixe pour éviter le CLS (Cumulative Layout Shift) */
.card-image {
aspect-ratio: 4 / 3;
width: 100%;
object-fit: cover;
}
.hero-image {
aspect-ratio: 16 / 9;
width: 100%;
object-fit: cover;
}
/* Ratio différent sur mobile */
@media (max-width: 767px) {
.hero-image {
aspect-ratio: 4 / 3;
}
}
```
### Flex et Grid — pièges courants
```css
/* Flex : min-width: 0 obligatoire pour éviter les débordements de texte */
.flex-item {
min-width: 0;
}
/* Flex wrap automatique */
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card-grid .card {
flex: 1 1 280px;
min-width: 0;
}
/* Grid responsive sans media query */
.auto-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
/* Grid : colonne unique sur mobile, deux colonnes sur desktop */
.two-col {
display: grid;
grid-template-columns: 1fr;
gap: 24px;
}
@media (min-width: 768px) {
.two-col {
grid-template-columns: 1fr 1fr;
}
}
```
### Safe area insets (encoche, barre de navigation)
```css
/* Nécessite viewport-fit=cover dans la balise meta */
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 56px;
padding-bottom: env(safe-area-inset-bottom);
background: var(--color-bg);
}
.top-header {
position: fixed;
top: 0;
left: 0;
right: 0;
padding-top: env(safe-area-inset-top);
}
.main-content {
padding-bottom: calc(56px + env(safe-area-inset-bottom));
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
```
Si `viewport-fit=cover` n'est pas défini, les valeurs valent 0 — ces règles n'ont aucun effet négatif.
### prefers-reduced-motion
```css
/* Animations définies normalement */
.fade-in {
animation: fadeIn 0.4s ease;
}
/* Suppression globale si l'utilisateur le demande */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* Approche plus granulaire */
@media (prefers-reduced-motion: reduce) {
.fade-in {
opacity: 1;
animation: none;
}
}
```
### prefers-color-scheme — dark mode
```css
:root {
--color-bg: #ffffff;
--color-text: #1a1a1a;
--color-text-muted: #6b7280;
--color-border: #e5e7eb;
--color-surface: #f9fafb;
--color-primary: #2563eb;
--color-primary-text: #ffffff;
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #0f172a;
--color-text: #e2e8f0;
--color-text-muted: #94a3b8;
--color-border: #1e293b;
--color-surface: #1e293b;
--color-primary: #3b82f6;
--color-primary-text: #ffffff;
--shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}
img:not([src*=".svg"]) {
filter: brightness(0.9);
}
}
/* Toggle manuel qui coexiste avec la préférence système */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--color-bg: #0f172a;
/* ... */
}
}
[data-theme="dark"] {
--color-bg: #0f172a;
/* ... */
}
[data-theme="light"] {
--color-bg: #ffffff;
/* ... */
}
```
### Formulaires
```css
input[type="text"],
input[type="email"],
input[type="password"],
input[type="tel"],
input[type="number"],
textarea,
select {
width: 100%;
font-size: 16px; /* obligatoire — empêche zoom iOS */
padding: 12px 16px;
min-height: 44px;
border-radius: 8px;
border: 1px solid var(--color-border);
-webkit-appearance: none;
appearance: none;
background: var(--color-bg);
color: var(--color-text);
}
label {
display: block;
font-size: 16px;
margin-bottom: 6px;
font-weight: 500;
}
.form-group {
margin-bottom: 20px;
}
```
Attributs HTML à ne pas oublier (CSS ne peut pas les remplacer) :
```html
<!-- Clavier numérique -->
<input type="text" inputmode="numeric">
<!-- Clavier décimal -->
<input type="text" inputmode="decimal">
<!-- Clavier email avec @ direct -->
<input type="email" inputmode="email">
<!-- Clavier URL -->
<input type="url" inputmode="url">
```
### Espacement latéral minimum
```css
.container {
padding-left: 16px; /* minimum absolu sur mobile */
padding-right: 16px;
max-width: 1200px;
margin: 0 auto;
}
@media (min-width: 768px) {
.container {
padding-left: 24px;
padding-right: 24px;
}
}
@media (min-width: 1024px) {
.container {
padding-left: 32px;
padding-right: 32px;
}
}
```
---
## Section 4 : Conventions CSS — règles génériques
### CSS custom properties pour le theming
Toujours définir les valeurs répétées en custom properties. Jamais de couleurs ou d'espacements en dur dispersés dans le CSS.
```css
:root {
/* Couleurs */
--color-primary: #2563eb;
--color-primary-hover: #1d4ed8;
--color-bg: #ffffff;
--color-text: #1a1a1a;
--color-text-muted: #6b7280;
--color-border: #e5e7eb;
--color-surface: #f9fafb;
--color-danger: #dc2626;
--color-success: #16a34a;
/* Espacements */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
--space-xl: 32px;
--space-2xl: 48px;
/* Typographie */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--line-height-base: 1.6;
--line-height-tight: 1.3;
/* Rayons */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-full: 9999px;
/* Ombres */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
/* Transitions */
--transition-fast: 0.15s ease;
--transition-base: 0.25s ease;
}
```
### Conventions de nommage
Être cohérent. BEM ou utility-first, pas les deux mélangés dans le même projet.
**BEM** (conseillé pour les composants isolés) :
```css
/* Block */
.card {}
/* Element */
.card__title {}
.card__body {}
.card__footer {}
/* Modifier */
.card--featured {}
.card--compact {}
.card__title--large {}
```
### Accessibilité
**focus-visible** — ne jamais supprimer l'outline sans le remplacer :
```css
/* ❌ À ne jamais faire */
* { outline: none; }
:focus { outline: none; }
/* ✅ Remplacer l'outline natif par un style custom */
:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
border-radius: 2px;
}
/* Supprimer l'outline seulement pour les clics souris (pas clavier) */
:focus:not(:focus-visible) {
outline: none;
}
```
**Contrastes WCAG AA** :
| Contexte | Ratio minimum |
|----------|--------------|
| Texte normal (< 18px) | 4.5:1 |
| Texte large (≥ 18px ou ≥ 14px bold) | 3:1 |
| Composants UI, icônes | 3:1 |
### Performance CSS
```css
/* ❌ Déclenche du repaint sur chaque frame d'animation */
.card:hover {
box-shadow: 0 8px 30px rgba(0,0,0,0.2);
}
/* ✅ Mieux : préparer l'ombre au chargement, changer l'opacité */
.card {
box-shadow: 0 8px 30px rgba(0,0,0,0);
transition: box-shadow var(--transition-base);
}
.card:hover {
box-shadow: 0 8px 30px rgba(0,0,0,0.2);
}
/* ✅ Utiliser opacity ou transform — composités sur le GPU */
.element {
transform: translateY(0);
opacity: 1;
transition: transform var(--transition-base), opacity var(--transition-base);
}
.element.hidden {
transform: translateY(8px);
opacity: 0;
}
```
### CSS moderne à privilégier
```css
/* clamp() — tailles fluides sans media queries */
h1 { font-size: clamp(1.5rem, 5vw, 2.5rem); }
.container { padding: clamp(16px, 4vw, 48px); }
/* gap — plus lisible que margin sur les enfants */
.grid {
display: flex;
gap: 24px;
}
/* aspect-ratio — plus fiable que le padding-top hack */
.video-wrapper {
aspect-ratio: 16 / 9;
width: 100%;
}
/* Propriétés logiques — pour le multilinguisme (RTL/LTR) */
.card {
margin-inline: auto;
padding-block: 24px;
border-inline-start: 3px solid var(--color-primary);
}
/* inset — remplace top/right/bottom/left */
.overlay {
position: fixed;
inset: 0;
}
```
### Règle sur !important
`!important` est accepté uniquement dans deux cas :
1. Classes utilitaires (`.sr-only`, `.hidden`, `.visually-hidden`) — par convention
2. Override de styles tiers qu'on ne contrôle pas (plugins, librairies)
En dehors de ces cas, un `!important` signale un problème de spécificité à corriger à la source.
---
## Section 5 : Checklist de test
### Devices à tester
| Device | Largeur | Priorité |
|--------|---------|----------|
| iPhone SE (2020/2022) | 375px | Haute — écran le plus étroit mainstream |
| iPhone 14 / 15 | 390px | Haute — référence iOS courante |
| Android mid-range (Pixel 6a, Samsung A54) | 360–412px | Haute |
| iPad / iPad Mini | 768px | Moyenne |
| Desktop laptop | 1280–1440px | Baseline |
### Modes à tester
- [ ] Portrait (défaut)
- [ ] Paysage (landscape)
- [ ] Dark mode
- [ ] Reduced motion
- [ ] Zoom texte à 150%
### Lighthouse — cibles
| Score | Cible |
|-------|-------|
| Performance | ≥ 80 |
| Accessibility | ≥ 90 |
| Best Practices | ≥ 90 |
| SEO | ≥ 90 |
### Checklist finale
- [ ] Aucun scroll horizontal sur aucun device testé
- [ ] Tous les éléments interactifs accessibles au clavier (Tab + Enter/Space)
- [ ] focus-visible visible et distinctif
- [ ] Tous les inputs avec font-size ≥ 16px
- [ ] Textes avec contraste ≥ 4.5:1 (normal) ou 3:1 (grand)
- [ ] Images avec `alt` descriptif ou `alt=""` si décoratif
- [ ] Formulaires avec `<label>` associé à chaque input
- [ ] Dark mode : texte lisible, pas de blanc éblouissant
- [ ] Reduced motion : aucune animation qui se joue quand même
- [ ] Lighthouse Accessibility ≥ 90
- [ ] Pas de zoom automatique iOS sur les inputs
- [ ] Touch targets ≥ 44×44px
Télécharger le fichier
Le fichier est disponible directement :
Télécharger le CLAUDE.md.
À coller à la racine du projet ou dans .claude/.
La suite
L'idée derrière ce fichier, c'est de construire une collection de CLAUDE.md spécialisés par type de tâche. Pas un CLAUDE.md générique qui essaie de tout couvrir et devient illisible, mais des fichiers ciblés qu'on active selon le chantier en cours. Mobile CSS, tests unitaires Go, migrations PostgreSQL, audit de sécurité — chacun avec son contexte précis, ses cibles, ses pièges.
Celui-ci est le premier de la série. Si vous avez des contextes spécialisés que vous utilisez déjà, ou des tâches pour lesquelles vous aimeriez un fichier du même genre, les commentaires sont ouverts.