Files
_Assistant_Lead_Tech/knowledge/frontend/risques/responsive.md
T
MaksTinyWorkshop 5f5c87296e docs(knowledge): capitalisation frontend — intégration du triage local (mai-juin 2026)
Triage et intégration des propositions frontend du buffer 95_a_capitaliser.md
(lot local RL799_V2/Vue3 + app-alexandrie/RN-Expo, mai-juin 2026).

~73 entrées intégrées sur knowledge/frontend/ + 1 nouveau fichier, dont :
- patterns/state.md : race-token partagé latest-wins (fusion 3 props), capture sync anti-race,
  event bus timestamp, clé cache composite, état dérivé = computed
- risques/state.md : 9 risques Zustand/store (fetchId reset, useRef remount, re-fetch infini
  sur [], flag optimiste écrasé, cache détail/liste stale, latch sans reset, :key index)
- patterns/navigation.md : Expo Router (tab bar, useFocusEffect, Href typé, routing pur fusionné)
- patterns/general.md : helpers temps purs, composants génériques + skeleton, fail-fast, touch target
- risques/general.md : 24 risques (sweep statique, filtre client liste paginée, hooks avant return,
  a11y VoiceOver/disabled, redirection allowlist, RangeError toISOString, section i18n...)
- design-tokens (cluster theming light/dark MD3), tests, performance, react-native, nextjs
- NOUVEAU risques/responsive.md (gating par capacité d'input + checklist régressions mobile)
- READMEs patterns/risques mis à jour

Doublons inter-fichiers évités (vérifié : aucune ancre dupliquée introduite).
Rejets (doublons 91/9/87), reciblages workflow (156/257) et bloc 32 (CLAUDE projet) non intégrés ici.
Source 95_a_capitaliser.md non purgée (purge en fin de capitalisation complète).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 15:31:53 +02:00

5.3 KiB

Frontend — Risques & vigilance : Responsive / adaptation mobile

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


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).

@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é */ }
// é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

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