# Frontend — Risques & vigilance : Responsive / adaptation mobile

> Extrait de la base de connaissance Lead_tech. Voir `knowledge/frontend/risques/README.md` pour l'index complet.

---

<a id="risque-gating-responsive-largeur-vs-input"></a>
## Gating responsive par largeur seule → fuite sur tablettes tactiles

### Risques

- Le réflexe `@media (min-width: 768px|900px|1024px)` traite la largeur comme un proxy de l'UX cible ; ça casse sur **tablettes tactiles** (iPad Air 1180px, iPad Pro 1366px, Surface, Galaxy Tab) qui ont la largeur d'un desktop mais l'UX d'un doigt
- Conséquences observées : swipe gestures désactivés sur iPad (alors que le swipe est l'UX tactile naturelle), scrollbars custom visibles en permanence, hover states bloquants au tap (1er tap = hover, 2e = click), pagination trop dense pour le doigt

### Symptômes

- Une règle "desktop" gated par `min-width` seul se comporte mal sur iPad : interactions désactivées ou inadaptées, scrollbars inutiles

### Bonnes pratiques / mitigations

**Gater par capacité d'input dès que la règle concerne une interaction** (hover, swipe, scrollbar visible, densité tactile, drag-and-drop, focus-ring discret).

```css
@media (pointer: fine)   { /* souris/trackpad précis : desktop, laptop */ }
@media (pointer: coarse) { /* doigt/stylet imprécis : mobile, tablette tactile */ }
@media (hover: hover)    { /* hover stable */ }
@media (hover: none)     { /* hover simulé (tap) */ }

/* "Vraie expérience desktop" : largeur ≥ X ET souris */
@media (pointer: fine) and (min-width: 900px) { /* scrollbars custom, hover, pagination dense */ }

/* "Expérience tactile" : doigt, peu importe la largeur */
@media (pointer: coarse) { /* swipe, touch targets ≥44px, pas de hover stylé */ }
```

```ts
// équivalent runtime
const isFinePointer = window.matchMedia('(pointer: fine)').matches;
const isCoarseLarge = window.matchMedia('(pointer: coarse) and (min-width: 900px)').matches;
```

- **Garder `min-width` seul** pour le **layout pur** (grille, max-width container) : la largeur détermine la place, pas l'input.
- Critère de décision : « Si je donne à un user iPad cette règle, préfère-t-il le comportement mobile ou desktop ? » Réponse "mobile" (swipe, touch dense) → `pointer: coarse` ; réponse "desktop" (layout 2 colonnes, max-width) → `min-width` seul. Doute → `pointer: fine` + `min-width`.
- Support : `pointer:` / `hover:` (Interaction Media Features L4) universel depuis 2018, aucun fallback en 2026. Pattern CSS pur, applicable à toute stack.
- Contexte technique : Vue 3 / Vite — RL799_V2 (chantier `feat/desktop-experience`, swipe rows / scrollbar globale / pagination Audit), 12-05-2026

---

<a id="risque-regressions-mobile-chantier-desktop"></a>
## Régressions mobile invisibles lors d'un chantier desktop responsive

### Risques

- Un chantier "ajout desktop" sur une app mobile-first crée des régressions mobile par **effets de bord indirects**. Les devs travaillent en majorité sur viewport desktop → les régressions mobile n'apparaissent qu'au test final sur device, tardivement
- 4 vecteurs récurrents : wrappers retirés qui fournissaient un gap implicite, classes globales qui cumulent leurs paddings, `display: contents`/grid qui change l'ordre DOM mobile, règles `min-width` qui fuient sur tablette tactile

### Symptômes

- "Les espaces ont été mangés" (éléments mobiles collés), "le contenu est plus étroit qu'avant" (marges doublées), "l'ordre des cartes a changé" sans changement mobile intentionnel

### Bonnes pratiques / mitigations

Les 4 vecteurs et leur fix :

1. **Wrapper retiré → gap implicite perdu** : un `<PageShell>`/`<ContentCard>` retiré côté desktop portait un `gap`/`padding-top` qui structurait le rythme mobile. Fix : remettre explicitement `gap: var(--space-X)` sur le nouveau wrapper mobile, mesurer en pixels avant/après.
2. **Classes globales qui cumulent les paddings** : `.tenue-detail-container { padding-inline: 16px }` + `.page--dashboard { padding-inline: 16px }` = 32px sur mobile. Fix : neutraliser côté mobile (`.page--dashboard .tenue-detail-container { padding-inline: 0; }`).
3. **`display: contents` qui change l'ordre DOM mobile** : sur mobile le wrapper transparent fait suivre l'ordre HTML (réordonné pour le desktop), pas l'ordre historique mobile. Fix : préserver l'ordre via `flex` + `order` en `@media (max-width: 899px)`.
4. **Règles `@media (min-width)` qui fuient sur tablette tactile** : cf. `#risque-gating-responsive-largeur-vs-input`. Fix : ajouter `and (pointer: fine)` aux règles concernant une interaction.

**Checklist QA mobile post-chantier desktop** (avant merge) :

1. Audit gap/padding mobile (diff visuel page par page vs version précédente)
2. Audit ordre DOM mobile pour chaque page touchée (surtout `display: contents`/grid)
3. Grep `@media (min-width:` dans le diff ; pour chaque règle concernant une interaction, ajouter `and (pointer: fine)`
4. Audit cumul de paddings : pour chaque nouvelle classe wrapper, vérifier qu'aucune classe interne globale n'ajoute son propre `padding-inline`
5. Test sur appareil **physique** réel (iPhone + Android + iPad tactile), pas seulement les émulateurs DevTools (qui simulent la largeur mais pas la nature du pointer)

- Contexte technique : Vue 3.5 / Vite 7 — RL799_V2 (chantier `feat/desktop-experience`, passe QA mobile ~2h sur 7 fichiers), 12-05-2026
