Tables réactives pour la documentation technique qui tiennent en production

Cet article vous a aidé ?

Vous publiez un élégant tableau de référence d’API. Il est parfait sur votre écran 32 pouces. Puis le support envoie une capture d’écran d’un téléphone où le tableau
s’est échappé de la page comme un chat errant, repoussant la navigation hors écran et rendant les boutons « Copier » inaccessibles.

Les tableaux sont le mode d’échec silencieux des docs techniques : ils fonctionnent jusqu’à ce qu’ils ne fonctionnent plus, et quand ça casse, ils emmènent le reste de la mise en page avec eux.
Voici une méthode pratique, de niveau opérationnel, pour construire des tableaux réactifs : un conteneur de défilement qui se comporte, des en‑têtes collants qui ne tremblent pas, et des cellules de code toujours lisibles.

Principes non négociables : ce que « tableau réactif » veut dire réellement

« Tableau réactif » n’est pas « rendre plus petit jusqu’à ce que ça rentre. » Dans la documentation technique, les tableaux contiennent des informations denses et à fort enjeu :
paramètres, valeurs par défaut, matrices de compatibilité, codes de sortie, limites de stockage, et le genre de notes de bas de page qui évitent des pages cassées le week‑end.
Votre travail est de maintenir la véracité et l’utilisabilité du tableau sur tous les écrans et méthodes d’entrée.

Principe 1 : Ne transformez pas la vérité en fiction

Beaucoup de recettes « tableau réactif » empilent les colonnes en cartes. Cela peut convenir pour des pages marketing.
Dans la doc, ça transforme souvent des comparaisons en chasse au trésor. Si le lecteur doit comparer des valeurs entre colonnes, préservez la grille.
Le défilement horizontal est acceptable quand il est volontaire et ne casse pas le reste.

Principe 2 : Le tableau n’a pas le droit de s’échapper de son conteneur

Le mode d’échec principal est l’overflow : des chaînes non cassées (UUID, base64, SHA256, chemins de fichiers, commandes) forcent le tableau à être plus large que la fenêtre.
Une fois arrivé là, la mise en page devient « créative ». Corrigez‑le au niveau du conteneur et au niveau des cellules. Les deux.

Principe 3 : Les en‑têtes collants doivent rester alignés avec les colonnes

Les en‑têtes collants sont une fonctionnalité de productivité — jusqu’à ce qu’ils dérivent hors alignement à cause de largeurs inconsistantes, de modèles de bordure ou de contextes de défilement imbriqués.
Un en‑tête collant qui ne correspond pas à sa colonne est pire que pas d’en‑tête collant. Cela transforme la lecture en devinette.

Principe 4 : Les cellules de code ne sont pas de la prose

Le code inline est souvent long, copié/collé, et lu en scannant. Il nécessite une police monospace, des règles de retour à la ligne sensées et un fond qui fonctionne en mode sombre.
« Laissez simplement aller à la ligne » n’est pas une stratégie ; c’est comment on obtient des jetons cassés (et des déploiements cassés).

Principe 5 : Si ce n’est pas accessible au clavier, ce n’est pas fini

Les conteneurs de défilement peuvent piéger le focus, les en‑têtes collants peuvent chevaucher les contours de focus, et les boutons de copie peuvent devenir inaccessibles.
Assurez‑vous d’un état de focus visible et d’une expérience de défilement stable pour le tactile et le clavier.

Une citation que j’utilise quand certains veulent « livrer et voir » l’UI de la doc : L’espoir n’est pas une stratégie. — General Gordon R. Sullivan

Blague #1 : Les en‑têtes collants sont comme les rotations d’astreinte : super jusqu’à ce qu’ils dérivent, puis tout le monde se dispute la responsabilité.

Quelques faits et un peu d’histoire (parce que le web laisse des traces)

  • Les tableaux HTML précèdent les mises en page CSS et servaient à la mise en page dans les années 1990 ; la réaction explique pourquoi le style des tableaux reste capricieux dans certains cas limites.
  • position: sticky a été conçu pour réduire les gestionnaires de scroll en JavaScript — un gain de performance devenu essentiel pour les en‑têtes collants et les barres latérales.
  • Les navigateurs mobiles traitaient historiquement l’overflow et le chaînage de scroll différemment, d’où le fait que « ça marche sur desktop » n’implique pas « ça marche sur téléphone ».
  • Les jetons longs se sont généralisés dans la doc à cause de l’infra moderne : digests de conteneurs, IDs cloud, JWT, checksums et IDs de tracing sont des chaînes non cassées par conception.
  • Les patterns de copie dans le presse‑papier se sont popularisés avec la montée des outils DevOps ; ils sont désormais attendus pour commandes et snippets — même à l’intérieur des tableaux.
  • La technique table-layout: fixed est plus ancienne que beaucoup de design systems, et reste l’un des meilleurs leviers pour des largeurs de colonne prévisibles sous contrainte.
  • Le CLS (Cumulative Layout Shift) est devenu une métrique officielle avec Core Web Vitals ; les tableaux avec web fonts et contenu chargé tardivement sont des contrevenants fréquents.
  • Beaucoup de sites de doc sont des builds statiques (SSG), mais les tableaux peuvent quand même « rendre lentement » à cause de l’hydratation client, du highlighting et d’un CSS lourd.

Le modèle de base : conteneur de défilement + tableau résilient

Le défaut le plus sûr pour les tableaux de documentation technique est ennuyeux :
enveloppez le tableau dans un conteneur de défilement qui prend en charge l’overflow horizontal, gardez la largeur du tableau stable, et appliquez des règles de retour à la ligne au niveau des cellules
pour empêcher qu’un seul jeton n’explose la mise en page.

Structure HTML que vous pouvez déployer

Le wrapper n’est pas optionnel. Appliquer overflow-x: auto directement sur le tableau est peu fiable et peut casser les en‑têtes collants et le dimensionnement.
Faites du wrapper le conteneur de défilement ; gardez le tableau comme un tableau.

cr0x@server:~$ cat responsive-table.html
<div class="table-wrap" role="region" aria-label="API parameters table">
  <table class="doc-table">
    <thead>
      <tr>
        <th scope="col">Parameter</th>
        <th scope="col">Type</th>
        <th scope="col">Default</th>
        <th scope="col">Example</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th scope="row">timeout</th>
        <td>integer</td>
        <td>30</td>
        <td><code>timeout=60</code></td>
      </tr>
    </tbody>
  </table>
</div>

CSS qui tient sous pression

L’objectif est la stabilité : dimensionnement de colonne prévisible, overflow propre, et un conteneur de défilement qui n’hijacke pas la page.
Aussi : affordance visible. Si les utilisateurs ne réalisent pas qu’un tableau est défilable, ils supposent que la doc est cassée.

cr0x@server:~$ cat responsive-table.css
.table-wrap {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  border: 1px solid color-mix(in srgb, CanvasText 20%, transparent);
  border-radius: 10px;
  background: Canvas;
  max-width: 100%;
}

.doc-table {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  min-width: 720px;
  table-layout: fixed;
}

.doc-table th,
.doc-table td {
  padding: 0.75rem 0.9rem;
  vertical-align: top;
  border-bottom: 1px solid color-mix(in srgb, CanvasText 15%, transparent);
}

.doc-table thead th {
  background: color-mix(in srgb, Canvas 92%, CanvasText 8%);
  font-weight: 650;
}

.doc-table tbody tr:hover td,
.doc-table tbody tr:hover th[scope="row"] {
  background: color-mix(in srgb, Canvas 94%, CanvasText 6%);
}

.doc-table th[scope="row"] {
  font-weight: 600;
  text-align: left;
}

.doc-table td {
  overflow: hidden;
  text-overflow: ellipsis;
}

.doc-table code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-size: 0.95em;
  background: color-mix(in srgb, Canvas 88%, CanvasText 12%);
  padding: 0.12em 0.35em;
  border-radius: 6px;
  white-space: normal;
  overflow-wrap: anywhere;
}

Choix clés à faire délibérément :

  • min-width sur le tableau empêche « tout s’écrase en une bouillie illisible ». Sur petits écrans, le wrapper défile à la place.
  • table-layout: fixed réduit le coût de reflow et garde les largeurs de colonne prévisibles. Il permet aussi à l’ellipsis de fonctionner de façon cohérente.
  • Politique d’overflow au niveau des cellules : la prose normale peut s’enrouler ; le code et les identifiants doivent utiliser overflow-wrap: anywhere et ne jamais forcer la largeur.
  • L’ellipsis est un outil, pas un mensonge. Utilisez‑le quand une colonne est secondaire et que vous offrez un moyen de voir la valeur complète (attribut title, expansion, ou contrôle de copie).

En‑têtes collants qui ne scintillent pas, ne bavent pas et ne trompent pas

Les en‑têtes collants valent le coup pour les longs tableaux — matrices de compatibilité, inventaires de paramètres, listes de codes d’erreur.
Mais les en‑têtes collants ont trois problèmes classiques : (1) ils cessent d’être collants parce que le mauvais ancêtre défile,
(2) ils chevauchent le contenu et cachent le focus, ou (3) ils se désalignent par rapport aux colonnes.

Faites du wrapper le conteneur de défilement, puis collez‑y les en‑têtes

position: sticky colle par rapport à l’ancêtre scrollant le plus proche. Si vous avez mis de l’overflow sur un parent oublié,
votre en‑tête collera au mauvais élément — ou pas du tout.

cr0x@server:~$ cat sticky-header.css
.table-wrap {
  max-height: 60vh;
  overflow: auto;
}

.doc-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
}

.doc-table thead th::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: color-mix(in srgb, CanvasText 18%, transparent);
}

.doc-table thead th {
  box-shadow: 0 2px 0 color-mix(in srgb, CanvasText 10%, transparent);
}

Le z-index et une ombre subtile ne sont pas de la décoration. Ils apportent de la clarté. Sans eux, les utilisateurs ne savent pas où l’en‑tête se termine,
surtout en mode sombre et quand l’arrière‑plan de l’en‑tête est proche de celui du corps.

Alignement des en‑têtes collants : éviter les largeurs fractionnaires et le chaos des bordures

Le désalignement provient souvent du mélange de modes border-collapse, d’éléments imbriqués avec un box sizing différent, ou de contenu déclenchant le redimensionnement des colonnes.
Si vous voulez des en‑têtes collants, vous voulez des largeurs stables. C’est là que table-layout: fixed paye.

Si votre première colonne est une « clé de nom de paramètre » qui doit rester lisible, fixez‑lui une largeur :

cr0x@server:~$ cat column-widths.css
.doc-table th[scope="row"] {
  width: 14rem;
}

.doc-table td:nth-child(2) {
  width: 10rem;
}

.doc-table td:nth-child(3) {
  width: 8rem;
}

Première colonne collante : possible, mais ne le faites pas à la légère

Les premières colonnes collantes tentent pour les tableaux larges. Elles introduisent aussi des chevauchements et nécessitent la peinture d’arrière‑plan, le calage des z-index,
et une gestion soigneuse des bordures. Si vous en avez besoin, implémentez‑la — mais traitez‑la comme une fonctionnalité avec un plan de test, pas comme un astuce CSS mignonne.

cr0x@server:~$ cat sticky-first-column.css
.doc-table th[scope="row"] {
  position: sticky;
  left: 0;
  z-index: 1;
  background: Canvas;
}

.doc-table thead th:first-child {
  left: 0;
  z-index: 3;
  background: color-mix(in srgb, Canvas 92%, CanvasText 8%);
}

Cette dernière règle (la cellule coin supérieur gauche obtient le z-index le plus élevé) est la « taxe pour éviter un artefact de chevauchement bizarre ».
Payez‑la d’avance. Vous en paierez plus tard si vous ne le faites pas.

Cellules de code lisibles : jetons longs, possibilité de copier et retour à la ligne

Les tableaux de docs contiennent fréquemment : commandes, flags, fragments JSON, variables d’environnement, digests, regex et chemins.
Ces valeurs ne sont pas destinées à être lues comme un paragraphe ; elles sont destinées à être copiées, comparées et scannées.
Une cellule de code qui se replie aléatoirement peut créer une corruption invisible. C’est comme ça qu’on obtient des tickets « ça marchait en staging ».

Décidez : retour à la ligne, défilement ou coupe pour le code ?

Vous avez trois choix sensés pour les valeurs de type code :

  • Retour à la ligne n’importe où pour les identifiants dont les sauts de ligne n’altèrent pas le sens (IDs de ressources, hashes). Cela préserve la mise en page.
  • Défilement horizontal dans la cellule pour les commandes et configurations où les sauts peuvent induire en erreur. Cela préserve la possibilité de copier et la sémantique.
  • Couper avec ellipsis quand la valeur est secondaire et qu’il existe un affordance « copier la valeur complète ».

Ce que vous ne devriez pas faire : laisser le tableau s’agrandir au‑delà de son wrapper parce qu’un jeton refuse de se casser.
Ce n’est pas « réactif », c’est « hostile ».

Pattern : code défilable à l’intérieur d’une cellule

Une approche simple : rendre le code dans un élément de type bloc à l’intérieur de la cellule avec son propre défilement.
Cela évite de forcer l’ensemble du tableau à défiler juste parce qu’une cellule est longue.

cr0x@server:~$ cat code-cell.css
.doc-table td .cell-code {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  white-space: nowrap;
  padding: 0.35rem 0.5rem;
  border-radius: 8px;
  background: color-mix(in srgb, Canvas 88%, CanvasText 12%);
  border: 1px solid color-mix(in srgb, CanvasText 12%, transparent);
}

.doc-table td .cell-code code {
  white-space: inherit;
  background: transparent;
  padding: 0;
}

Pattern : préserver la possibilité de copier et montrer l’intention

Si vous rendez des sauts de ligne visibles dans une cellule de commande, les utilisateurs vont copier ces sauts. Ensuite ils collent dans un shell, et le shell fera des choses.
Pas toujours les choses voulues.

Utilisez white-space: nowrap pour les commandes sur une seule ligne ; n’utilisez des sauts explicites que si vous montrez volontairement un script multiligne et voulez qu’il soit copié ainsi.

Prévenir les bugs « semble un signe moins » dans le code

Certaines polices rendent différemment hyphen‑minus, en‑dash et em‑dash. Si votre pipeline de doc « améliore » la ponctuation,
vous pouvez finir avec des flags comme —help qui semblent corrects mais ne fonctionnent pas. La correction est principalement éditoriale (désactiver la ponctuation intelligente dans le code),
mais le rendu compte aussi : gardez le code dans des éléments code pour empêcher les moteurs typographiques d’innover.

Blague #2 : La seule chose plus dangereuse qu’une longue chaîne non cassée est la même chaîne cassée exactement au mauvais caractère.

Accessibilité et UX : ne pas punir les utilisateurs au clavier

Un conteneur de défilement est un petit modèle d’interaction. Si vous ne le concevez pas, les utilisateurs le découvriront à la dure.
Cela signifie : découvrabilité, comportement du focus, contraste lisible et défilement prévisible.

Donnez un rôle et un label au wrapper

Si le tableau déborde, les utilisateurs d’aides techniques doivent comprendre qu’ils sont dans une région avec son propre défilement.
Étiquetez‑la : « API parameters table », « Error codes table », pas « tableau » (ils savent déjà que c’est un tableau).

Focus visible : ne laissez pas les en‑têtes collants le cacher

Les en‑têtes collants peuvent couvrir le contenu focalisé quand un utilisateur tabule à travers des liens dans les cellules.
Prévoyez suffisamment de padding en haut de la zone de défilement, ou assurez‑vous que les éléments focalisés se mettent en vue avec une marge.

cr0x@server:~$ cat focus.css
.table-wrap {
  scroll-padding-top: 3rem;
}

.doc-table a:focus-visible,
.doc-table button:focus-visible,
.doc-table code:focus-visible {
  outline: 2px solid color-mix(in srgb, Highlight 80%, CanvasText 20%);
  outline-offset: 2px;
}

Ne comptez pas sur le hover pour transmettre de l’information

Le surlignage au survol est agréable sur desktop. Il ne fait rien sur le tactile et peu pour les utilisateurs au clavier.
Utilisez des bordures cohérentes, un zébrage si nécessaire, et gardez les en‑têtes de lignes/colonnes explicites (scope).

Respectez la réduction de mouvement et évitez le scroll‑jank

Les en‑têtes collants et les ombres sont acceptables. Le parallaxe à l’intérieur d’un wrapper de tableau ne l’est pas.
Toute animation liée au scroll devient « mon téléphone chauffe et le tableau ne défile toujours pas ».

Performance et modes de panne : quand les tableaux deviennent un incident de rendu

Les tableaux sont sournoisement coûteux. Le navigateur doit calculer les largeurs de colonne sur toutes les lignes, peindre les bordures, gérer les contextes de stacking collants,
et reflow quand les polices chargent ou quand des scripts côté client « améliorent » le balisage.
Si votre plateforme de docs fait de l’hydratation côté client, un grand tableau peut provoquer un blocage perceptible du thread principal.

Ce qui tend à nuire

  • Les très grands tableaux avec des centaines de lignes et du contenu cellulaire complexe (icônes, blocs imbriqués, syntax highlighting).
  • Les web fonts chargées tard qui changent les métriques et forcent la relayout, surtout avec position: sticky.
  • Les « plugins tableau » JavaScript qui réécrivent le DOM, mesurent les largeurs au scroll, ou attachent des écouteurs sans throttling.
  • Les grosses ombres et filtres appliqués à de nombreuses cellules.
  • Un bouton de copie par cellule rendu comme contrôle interactif à chaque ligne sans virtualisation.

Ce qui tend à aider

  • Gardez le HTML simple. Les tableaux ont déjà des règles de mise en page complexes ; ne les imbriquez pas de dashboards interactifs.
  • Utilisez table-layout: fixed pour un dimensionnement prévisible et moins de recalculs de layout.
  • Préférez le sticky CSS au JS. Les handlers de scroll sont la façon de transformer une « page de docs » en « mineur de crypto ».
  • Soyez intentionnel sur le syntax highlighting. Si vous highlightz des milliers de tokens côté client dans des tableaux, vous choisissez la douleur.
  • Limitez la hauteur pour les tableaux monstres afin que le défilement de la page reste sensé et que le défilement du tableau reste localisé.

Si votre site de doc a un budget de performance (et il devrait), les tableaux en font partie. Personne n’ouvre un incident parce que « la liste de paramètres est lente » ,
mais on en ouvre un parce que le train de release est retardé lorsqu’on ne peut pas lire la doc.

Trois mini‑histoires d’entreprise depuis le front

Incident : une mauvaise hypothèse sur « les utilisateurs mobiles ne lisent pas les tableaux »

Une équipe plateforme interne a livré un nouveau thème docs avec une « simplification mobile ». Sous un certain breakpoint, les tableaux étaient convertis en cartes empilées.
Chaque ligne devenait une carte ; chaque colonne devenait une paire étiquette/valeur. C’était propre. Produit a validé. Personne n’a essayé de comparer deux colonnes côte à côte.

Les premiers vrais utilisateurs étaient des ingénieurs d’astreinte consultant une matrice de compatibilité pendant une mise à jour.
Ils devaient comparer « client version », « server version » et « supported cipher suites ». La vue en cartes demandait un défilement sans fin et de la mémoire.
Les gens ont commencé à faire des captures d’écran de la version desktop depuis leurs portables et à les envoyer sur téléphone parce que c’était plus rapide que la vue mobile.

Puis est arrivée la panne de second ordre : le convertisseur de cartes a supprimé scope="row" et aplati le HTML.
Les utilisateurs de lecteurs d’écran se sont retrouvés avec des valeurs sans label. L’équipe l’a appris non pas via un audit d’accessibilité, mais via une escalade support.

La correction a été franche et correcte : préserver la grille du tableau sur mobile en utilisant un conteneur de défilement, ajouter un affordance visible « Faire défiler horizontalement »,
et garder l’en‑tête collant. La conversion en cartes est restée limitée à un petit sous‑ensemble de tableaux explicitement marqués « non comparatifs ».

Optimisation qui a mal tourné : « auto‑redimensionnons les colonnes en JS »

Une équipe docs voulait des largeurs de colonne parfaites : « Type » étroite, « Description » plus large, et « Example » juste assez grand. Ils ont implémenté un script mesurant
la cellule la plus large par colonne après le rendu, puis mettant des largeurs explicites sur les cellules d’en‑tête. Ça fonctionnait sur leurs pages de test.

En production, le site docs utilisait la navigation côté client et le chargement différé des polices. Chaque navigation déclenchait une nouvelle mesure.
Quand la police changeait, les largeurs évoluaient encore. Les en‑têtes collants maintenant tremblaient parce que les largeurs étaient mises à jour en plein scroll.
Sur les appareils bas de gamme, la boucle de mesure provoquait du jank perceptible — exactement là où vous voulez un défilement fluide.

Un bug particulièrement coriace est apparu quand des cellules de code contennaient des blocs défilables horizontalement.
Le script mesurait la scrollWidth, pas la largeur visible, et élargissait les colonnes à la longueur complète de la commande.
Le wrapper a cessé de contenir l’overflow. Le tableau s’est « échappé », de nouveau.

La correction finale fut délicieusement peu sexy : supprimer le sizing JavaScript, adopter table-layout: fixed, définir quelques largeurs de colonnes,
et utiliser ellipsis + copie pour les exemples extrêmement longs. La perfection a été échangée contre la prévisibilité, et tout le monde a mieux dormi.

Pratique ennuyeuse mais correcte qui a sauvé la mise : tester les tableaux avec du contenu pire‑cas

Une autre organisation exécutait la doc pour un produit régulé. Leur processus de revue n’était pas glamour, mais il était discipliné.
Chaque changement de thème majeur avait une « page torture pour tableaux » : identifiants énormes, JSON multi‑ligne, chemins longs, scénarios de ponctuation semblable à RTL,
et scripts mixtes. Rien de fancy. Juste le pire contenu qu’ils auraient jamais vu en production.

Lors d’une refonte, une nouvelle règle CSS a mis white-space: nowrap sur tous les td pour « garder les choses propres ».
La page torture a immédiatement montré de l’overflow horizontal sur tout le site, pas seulement dans les wrappers de tableaux.
La régression a été détectée avant la fusion.

Ils avaient aussi un check d’accessibilité : tabuler dans la région du tableau jusqu’à atteindre le dernier lien de la dernière ligne.
Si le focus disparaissait derrière l’en‑tête collant, le changement ne passait pas.

La pratique ennuyeuse — garder une page pire‑cas et la traiter comme une suite de tests — a empêché un déploiement qui aurait cassé chaque tableau de référence d’API.
Personne n’a écrit de postmortem parce que rien n’a cassé. C’est le meilleur type de travail de fiabilité.

Playbook de diagnostic rapide : quoi vérifier en premier/deuxième/troisième

Quand un tableau est « cassé » (overflow, lenteur, désalignement, illisibilité), vous voulez éviter le whack‑a‑mole CSS aléatoire.
Exécutez ceci dans l’ordre. C’est conçu pour trouver le goulot rapidement.

1) Identifier le propriétaire du scroll

  • Le wrapper est‑il l’élément avec overflow-x/overflow ?
  • Un parent crée‑t‑il accidentellement un conteneur de défilement ?
  • Le tableau est‑il plus large que le wrapper à cause d’un jeton non cassable ?

2) Trouver la cellule la plus large (le suspect habituel)

  • Cherchez des identifiants longs, base64, JSON minifié, ou commandes sans coupures.
  • Vérifiez si white-space: nowrap est appliqué trop largement.
  • Vérifiez la présence de min-width sur des cellules ou éléments enfants forçant la largeur.

3) Valider le comportement sticky dans le contexte de scroll réel

  • Les en‑têtes collants ont besoin de position: sticky; top: 0 sur th et d’un conteneur de défilement défini.
  • Vérifiez les contextes de stacking (z-index) pour que l’en‑tête peint au‑dessus des lignes du corps.
  • Confirmez que l’arrière‑plan de l’en‑tête est opaque ; sinon le texte du corps traverse pendant le scroll.

4) Vérifier la stabilité du layout et le coût de rendu

  • Si c’est saccadé, vérifiez si du JavaScript mesure les largeurs ou réagit au scroll.
  • Vérifiez le swap de police (FOIT/FOUT) et s’il cause une relayout du tableau.
  • Vérifiez si le syntax highlighting se fait côté client pour des centaines de cellules.

5) Confirmer l’utilisabilité clavier/tactile

  • Pouvez‑vous focaliser dans la région et voir l’anneau de focus ?
  • Le défilement horizontal tactile fonctionne‑t‑il sans déclencher les gestes de navigation de page ?
  • L’en‑tête collant couvre‑t‑il des éléments focalisés ?

Tâches pratiques : commandes, sorties et décisions (12+)

Ce sont des tâches « faites le truc » que vous pouvez exécuter sur un repo de docs ou sur un site construit. Chaque tâche inclut : une commande, une sortie d’exemple, ce que ça signifie,
et la décision que vous en tirez. Elles supposent un build de site statique typique, avec artefacts HTML/CSS/JS.

Task 1: Find tables that aren’t wrapped (the root of most overflow bugs)

cr0x@server:~$ rg -n "

Ce que ça signifie : Vous avez plusieurs variantes de tableaux ; certains peuvent manquer du wrapper.

Décision : Standardisez sur un composant wrapper unique (.table-wrap) et échouez la build quand un tableau nu apparaît dans le contenu.

Task 2: Identify unwrapped tables via HTML parsing

cr0x@server:~$ python3 - <<'PY'
from bs4 import BeautifulSoup
import glob, sys
bad=[]
for f in glob.glob("public/**/*.html", recursive=True):
    html=open(f,encoding="utf-8").read()
    s=BeautifulSoup(html,"html.parser")
    for t in s.find_all("table"):
        p=t.parent
        if not (p and p.name=="div" and "table-wrap" in (p.get("class") or [])):
            bad.append((f, t.get("class")))
            break
print("unwrapped_files", len(set(x[0] for x in bad)))
for f,_ in bad[:10]:
    print(f)
PY
unwrapped_files 2
public/errors.html
public/compat.html

Ce que ça signifie : Deux pages ont des tableaux sans le conteneur de défilement attendu.

Décision : Corrigez ces templates/contenus maintenant ; sinon un jeton long peut casser toute la mise en page de la page.

Task 3: Detect “nowrap everywhere” CSS regressions

cr0x@server:~$ rg -n "white-space:\s*nowrap" public/assets/*.css | head -n 20
public/assets/app.css:1132:.doc-table td { white-space: nowrap; }
public/assets/app.css:1180:.cell-code { white-space: nowrap; }

Ce que ça signifie : La première règle est dangereuse ; elle force chaque cellule à refuser le retour à la ligne.

Décision : Retirez nowrap du td générique ; conservez nowrap seulement pour les conteneurs de code explicites.

Task 4: Confirm sticky header rules exist and target the right element

cr0x@server:~$ rg -n "position:\s*sticky" public/assets/*.css
public/assets/app.css:1202:.doc-table thead th { position: sticky; top: 0; z-index: 2; }

Ce que ça signifie : Sticky est appliqué sur thead th, qui est la bonne cible.

Décision : Gardez‑le. Si sticky échoue à l’exécution, le problème vient probablement de l’ancêtre de scroll ou du clipping d’overflow, pas du CSS manquant.

Task 5: Find overflow clipping ancestors that break sticky

cr0x@server:~$ rg -n "overflow:\s*(hidden|clip)" public/assets/*.css | head
public/assets/theme.css:221:.content { overflow: hidden; }
public/assets/theme.css:418:.doc-container { overflow: clip; }

Ce que ça signifie : Des règles d’overflow sur des conteneurs externes peuvent clipper les en‑têtes collants ou les barres de défilement.

Décision : Supprimez ou scopez le clipping d’overflow. Si vous devez clipper, assurez‑vous que le wrapper du tableau n’est pas à l’intérieur du contexte de stacking clipé.

Task 6: Spot the long-token landmines in content

cr0x@server:~$ rg -n "[A-Za-z0-9+/]{120,}={0,2}" content/ | head
content/auth.md:77:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....
content/trace.md:54:Zm9vYmFyYmF6cXV4cXV1eGJhc2U2NA==...

Ce que ça signifie : Des chaînes de type base64/JWT existent. Elles vont faire exploser les tableaux à moins d’autoriser le wrapping ou le défilement local.

Décision : Assurez‑vous que les cellules de code utilisent overflow-wrap: anywhere ou un défilement interne ; ajoutez des affordances de copie si nécessaire.

Task 7: Check for table-layout policy (fixed vs auto)

cr0x@server:~$ rg -n "table-layout" public/assets/*.css
public/assets/app.css:1099:.doc-table { table-layout: fixed; }
public/assets/app.css:2055:.matrix { table-layout: auto; }

Ce que ça signifie : Vous avez des modes de layout incohérents. auto peut provoquer des reflows coûteux et des surprises de largeur.

Décision : Par défaut pour les tableaux de docs, privilégiez fixed. Gardez auto seulement quand vous avez vraiment besoin du sizing intrinsèque (rare).

Task 8: Measure how many tables exist (scale matters for performance)

cr0x@server:~$ find public -name "*.html" -print0 | xargs -0 rg -c "

Ce que ça signifie : 47 tableaux sur le site construit. Ce n’est pas énorme, mais suffisant pour que des améliorations JS globales fassent mal.

Décision : Évitez les scripts lourds par tableau ; privilégiez un comportement CSS‑first et progressif.

Task 9: Detect client-side table enhancements (JS plugins, measurement loops)

cr0x@server:~$ rg -n "(getBoundingClientRect|offsetWidth|scrollWidth).*(table|thead|th)" public/assets/*.js | head
public/assets/app.js:8812:const w = th.getBoundingClientRect().width;
public/assets/app.js:8820:table.style.width = table.scrollWidth + "px";

Ce que ça signifie : Le JavaScript mesure des largeurs d’en‑tête et force peut‑être la largeur du tableau sur scrollWidth. C’est un signal d’alerte.

Décision : Supprimez ou gatez cette logique. Remplacez par du sizing CSS. Si vous la gardez, exécutez‑la une fois, pas en boucle sur scroll/resize.

Task 10: Validate that tables remain within viewport in a headless check

cr0x@server:~$ node - <<'NODE'
const fs = require("fs");
const { JSDOM } = require("jsdom");
const html = fs.readFileSync("public/api.html","utf8");
const dom = new JSDOM(html);
const tables = [...dom.window.document.querySelectorAll("table")];
console.log("tables", tables.length);
console.log("wrapped", [...dom.window.document.querySelectorAll(".table-wrap table")].length);
NODE
tables 3
wrapped 2

Ce que ça signifie : Un tableau dans api.html n’est pas wrapper.

Décision : Corrigez la génération HTML. Vous voulez « wrapped equals tables » pour les tableaux de doc sauf exemption explicite.

Task 11: Check for CLS risk from late font loading in built HTML

cr0x@server:~$ rg -n "rel=\"preload\" as=\"font\"" public/*.html | head
public/index.html:18:<link rel="preload" as="font" href="/assets/fonts/Inter.woff2" type="font/woff2" crossorigin>

Ce que ça signifie : Les polices sont preloadées sur la page d’accueil, mais pas forcément sur les pages de doc.

Décision : Assurez‑vous que les pages de doc contenant de grands tableaux preloadent les polices critiques, ou utilisez une pile de polices aux métriques stables.

Task 12: Audit for insufficient contrast in table header backgrounds

cr0x@server:~$ rg -n "thead th.*background" public/assets/*.css
public/assets/app.css:1110:.doc-table thead th { background: #f7f7f7; }
public/assets/dark.css:90:.doc-table thead th { background: #151515; }

Ce que ça signifie : Vous avez des couleurs explicites ; le contraste dépend de la couleur du texte et des surfaces environnantes.

Décision : Validez le contraste sur les deux thèmes ; préférez les couleurs système (Canvas, CanvasText) ou des color‑mix avec garde‑fous.

Task 13: Catch tables inside containers that disable horizontal scroll

cr0x@server:~$ rg -n "\.table-wrap\s*\{[^}]*overflow-x:\s*(hidden|clip)" public/assets/*.css

Ce que ça signifie : Aucune correspondance. Bien : le wrapper est autorisé à défiler.

Décision : Gardez‑le ainsi. Si un refactor ajoute du clipping d’overflow ici, traitez‑le comme une régression.

Task 14: Ensure table wrapper has a max-width policy

cr0x@server:~$ rg -n "\.table-wrap\s*\{[^}]*max-width" public/assets/*.css
public/assets/app.css:1072:.table-wrap { max-width: 100%; }

Ce que ça signifie : Le wrapper contraint la largeur au viewport/conteneur.

Décision : Gardez max-width: 100%. Sans cela, des mises en page imbriquées peuvent s’étirer de manière inattendue.

Erreurs courantes : symptôme → cause racine → correction

1) Symptom: The table pushes the entire page sideways

Cause racine : Tableau non wrapper ou wrapper sans overflow-x: auto ; jetons non cassables ou nowrap global.

Correction : Enveloppez les tableaux dans un conteneur de défilement dédié. Ajoutez du wrapping au niveau des cellules pour le code/IDs (overflow-wrap: anywhere), et retirez le nowrap global.

2) Symptom: Sticky header doesn’t stick

Cause racine : Élément sticky dans un contexte non scrollant ; un ancêtre a overflow: hidden/clip ; ou les cellules d’en‑tête ne sont pas les éléments sticky.

Correction : Faites du wrapper le conteneur de défilement (overflow: auto) et mettez position: sticky sur thead th. Retirez le clipping d’overflow des ancêtres.

3) Symptom: Sticky header sticks, but columns don’t align

Cause racine : Les largeurs de colonne changent à cause du sizing intrinsèque ; modèles de bordure mixtes ; JS mesurant et appliquant des largeurs de façon inconsistent.

Correction : Utilisez table-layout: fixed, fixez des largeurs explicites pour les colonnes clés, et arrêtez la manipulation JS des largeurs.

4) Symptom: Long commands wrap and become misleading

Cause racine : Code rendu avec white-space: normal et pas de politique de défilement interne ; un retour doux inséré au milieu d’un flag.

Correction : Utilisez un bloc .cell-code avec white-space: nowrap et overflow-x: auto, plus un bouton de copie si pertinent.

5) Symptom: Copying from table cells produces weird spaces/newlines

Cause racine : Le style insère des pseudo‑éléments, des retours, ou la ponctuation intelligente ; des éléments imbriqués ajoutent du texte caché.

Correction : Gardez le code dans <code>/<pre> avec un minimum de décoration ; évitez le pseudo‑contenu dans le code ; désactivez la substitution typographique dans le pipeline de rendu du code.

6) Symptom: On iOS, horizontal scroll fights with page scroll

Cause racine : Chaînage de scroll ; wrapper sans momentum scrolling ; conteneur trop petit ou imbriqué dans un autre scroller.

Correction : Ajoutez -webkit-overflow-scrolling: touch et overscroll-behavior-x: contain. Évitez autant que possible les conteneurs de défilement imbriqués.

7) Symptom: Focus outline disappears behind the sticky header

Cause racine : L’en‑tête collant chevauche ; pas de scroll padding ; l’en‑tête a un z-index élevé et un fond opaque.

Correction : Ajoutez scroll-padding-top sur le wrapper et assurez‑vous que les éléments focusables ont un style de focus visible.

8) Symptom: Page becomes sluggish when scrolling a long table

Cause racine : Handlers de scroll JS ; lourdes ombres sur de nombreuses cellules ; highlighting/hydratation dans un DOM large.

Correction : Supprimez les handlers de scroll ; simplifiez le contenu des cellules ; pré‑rendez le highlighting à la build ; limitez la hauteur du wrapper et gardez le layout fixe.

9) Symptom: Header text bleeds with body text while scrolling

Cause racine : Arrière‑plan de l’en‑tête transparent ; artefacts GPU/compositing.

Correction : Utilisez un arrière‑plan opaque sur thead th et un séparateur subtil (bordure ou ombre).

10) Symptom: The table looks fine, but users don’t realize it scrolls

Cause racine : Pas d’affordance visuelle ; barres de scroll masquées par l’OS ; le wrapper se fond dans l’arrière‑plan de la page.

Correction : Ajoutez une bordure et une légère différence d’arrière‑plan au wrapper ; éventuellement un petit indice « Faire défiler » pour les écrans étroits.

Listes de contrôle / plan pas à pas

Pas à pas : livrer un composant tableau réactif

  1. Créez un composant wrapper unique qui rend <div class="table-wrap" role="region" aria-label="..."> autour du tableau.
  2. Faites du wrapper le propriétaire du scroll : overflow-x: auto, max-width: 100%, et considérez max-height pour les longs tableaux.
  3. Utilisez un sizing de tableau stable : table-layout: fixed, width: 100%, et un min-width réaliste pour la lisibilité.
  4. Implémentez des en‑têtes collants sur thead th avec top: 0, un z-index approprié, et un fond opaque.
  5. Définissez la politique d’overflow des cellules :
    • Colonnes de prose : retour à la ligne normal.
    • Colonnes d’ID/hash : overflow-wrap: anywhere.
    • Colonnes commande/config : utilisez un scroller interne .cell-code avec nowrap.
  6. Conservez la sémantique correcte : th scope="col" et th scope="row" pour les en‑têtes de ligne.
  7. Test clavier : tabulez dans le tableau, faites défiler le wrapper, et assurez‑vous que le focus reste visible sous l’en‑tête collant.
  8. Test mobile : vérifiez que le balayage horizontal fait défiler le tableau sans tirer toute la page sur le côté.
  9. Test performance : ouvrez la page avec le plus grand tableau ; assurez‑vous que le défilement reste fluide et qu’il n’y a pas de jitter après le chargement des polices.
  10. Verrouillez‑le : ajoutez un check CI qui rejette les tableaux non wrapper et les règles nowrap globales sur les cellules de tableau.

Checklist de release (édition « ne me faites pas caller »)

  • Tous les tableaux sont enveloppés dans .table-wrap sauf exemption explicite.
  • Les en‑têtes collants fonctionnent dans le contexte de scroll du wrapper et restent alignés.
  • Les jetons longs n’élargissent pas la mise en page ; ils s’enroulent ou défilent dans les cellules.
  • Les contours de focus sont visibles ; l’en‑tête collant ne cache pas les éléments focalisés.
  • Les couleurs du mode sombre préservent le contraste pour les en‑têtes et les chips de code.
  • Aucun JavaScript ne mesure les largeurs au scroll.
  • La « page torture pour tableaux » rend correctement sur un viewport étroit.

FAQ

1) Le défilement horizontal est‑il « acceptable » dans la documentation technique ?

Oui, quand le tableau est comparatif et que vous préservez la grille. Rendez le conteneur de défilement évident et gardez les en‑têtes collants.
Forcer une mise en cartes détruit souvent la valeur principale du tableau : la comparaison.

2) Pourquoi ne pas simplement utiliser une librairie JS de tableau ?

Parce que la plupart des tableaux de docs n’ont pas besoin de tri, pagination ou filtrage, et les librairies JS ajoutent du poids, du reflow et des bugs.
Si vous avez réellement besoin de ces fonctionnalités, implémentez‑les de manière progressive et gardez la base lisible sans JS.

3) Dois‑je mettre overflow-x: auto sur le <table> ?

Non. Mettez l’overflow sur un wrapper. Les tableaux ont un comportement de layout spécial ; les en‑têtes collants et les calculs de largeur se comportent plus prudemment
quand le tableau reste un élément table normal à l’intérieur d’un conteneur de défilement.

4) Quelle est la meilleure façon de gérer les commandes longues dans une cellule ?

Utilisez un bloc de code interne défilable (.cell-code) avec white-space: nowrap. Si la commande est critique, ajoutez un bouton de copie.
Évitez de faire revenir à la ligne les commandes sauf si vous affichez explicitement un script multiligne.

5) Pourquoi table-layout: fixed ? N’altère‑t‑il pas les colonnes ?

Ça peut, si vous ne définissez jamais de largeurs et que vous bourrez des contenus très différents dans les colonnes. Mais pour la doc, la prévisibilité vaut mieux que l’ingéniosité.
Fixez des largeurs pour les colonnes clés et laissez le reste partager l’espace restant. Cela réduit le thrash de layout et garde les en‑têtes collants alignés.

6) Comment garder un en‑tête collant lisible en mode sombre ?

Donnez‑lui un fond opaque et un séparateur subtil (bordure ou ombre). Les en‑têtes transparents en mode sombre tendent à bavurer visuellement pendant le scroll.
Préférez les couleurs système (Canvas/CanvasText) ou des valeurs mélangées avec précaution.

7) Qu’en est‑il de l’impression ?

Les styles d’impression doivent désactiver le positionnement sticky et retirer les limites de hauteur pour que le contenu s’écoule. Si vos tableaux sont larges, envisagez de
permettre qu’ils s’adaptent ou coupent proprement les pages. Ajoutez une feuille de style d’impression qui définit .table-wrap { overflow: visible; max-height: none; }.

8) Comment montrer la valeur complète quand j’utilise l’ellipsis ?

Fournissez un affordance explicite : un bouton de copie, un bascule « Développer », ou un tiroir de détails. Ne comptez pas seulement sur l’attribut title ;
il est incohérent sur mobile et pas idéal pour l’accessibilité.

9) Ai‑je besoin d’en‑têtes collants pour chaque tableau ?

Non. Utilisez‑les pour les longs tableaux où l’en‑tête porte du sens (colonnes de paramètres, matrices de compatibilité). Pour les petits tableaux, les en‑têtes collants
peuvent être un bruit visuel et ajouter une complexité inutile.

Conclusion : quoi changer dès lundi matin

Si vous retenez une chose : les tableaux ne « deviennent pas réactifs » par magie. Vous les rendez réactifs en contrôlant l’overflow et en stabilisant la mise en page.
Enveloppez les tableaux dans un conteneur de défilement, rendez les en‑têtes collants dans ce contexte de défilement, et traitez les cellules de code comme un problème de rendu séparé.

Prochaines étapes pratiques :

  • Implémentez un composant standard .table-wrap et migrez chaque tableau de docs vers lui.
  • Adoptez table-layout: fixed pour les tableaux de docs et fixez des largeurs pour les colonnes clés.
  • Ajoutez des politiques pour les cellules de code : wrap‑anywhere pour les IDs, défilement interne pour les commandes/config.
  • Créez une « page torture pour tableaux » et exécutez‑la à chaque changement de thème avant de livrer.
  • Retirez la mesure JavaScript des largeurs et tout comportement lié au scroll à moins de prouver sa nécessité.

Vos docs font partie de votre système de production. Traitez le composant tableau comme une dépendance critique : prévisible, testable, et ennuyeuse de la meilleure manière.

← Précédent
Debian 13 : /etc/pve semble vide après le redémarrage — pourquoi les montages échouent et comment récupérer
Suivant →
PostgreSQL vs Redis : empêcher les cache-stampedes de faire fondre votre base de données

Laisser un commentaire