CSS pour contenu Markdown : des valeurs par défaut sensées qui ne cassent pas la production

Cet article vous a aidé ?

Vous publiez une page de documentation. Quelqu’un colle un tableau Markdown à huit colonnes, un bloc de code avec une ligne de 300 caractères et une liste imbriquée qui ressemble à un recensement romain. Soudain, la mise en page se décale, la vue mobile affiche des barres de défilement horizontales, et l’équipe du design système arrive avec un rapport de bug comme preuve.

Markdown est « simple » jusqu’au moment où vous l’exécutez en production à grande échelle : multiples renderers, contenu inconnu, HTML imprévisible et CSS qui fuit joyeusement sur tout le site. Fixons des valeurs par défaut sensées — titres, listes, tableaux, code, citations — pour que votre contenu reste lisible et votre UI intacte.

Les principes de production : portée, prévisibilité et cas limites peu ragoûtants

Styliser Markdown n’est pas un exercice « choisis une belle police ». C’est sandboxer le contenu avec de la typographie. Vous prenez un contenu semi-structuré et le rendez à l’intérieur d’une UI produit qui a ses propres hypothèses sur l’espacement, les couleurs et la mise en page. En pratique, vous défendez le reste de la page contre le contenu, et vous défendez le contenu contre le reste du CSS.

Trois principes vous épargnent les ennuis :

  • Scopez tout. Placez le Markdown à l’intérieur d’un conteneur comme .md et ne stylisez que l’intérieur. Si vous publiez des règles globales pour h1, pre ou table, vous ne « stylisez pas Markdown ». Vous jouez au casino avec l’ensemble du site.
  • Privilégiez un rythme prévisible plutôt que des visuels ingénieux. Les utilisateurs lisent la doc sous stress : incident, migration, onboarding. Votre CSS devrait être ennuyeux dans le bon sens : espacement cohérent, longueur de ligne lisible, formatage de code sensé.
  • Concevez pour le pire input. URLs longues, hashes non cassés, listes profondément imbriquées, tableaux larges et blocs de code qui refusent d’à-couper. Si vous ne stylisez que le « chemin heureux », votre premier power user fera le QA à votre place.

Un point supplémentaire : faites faire moins de travail au navigateur. Les CSS sophistiqués qui déclenchent reflow, layout shifts ou paint storms transforment « une page de doc » en « incident de performance ». Oui, vraiment.

Idée paraphrasée de Werner Vogels (reliability engineering) : on construit des systèmes en supposant l’échec, puis on rend l’échec survivable. Cela s’applique aussi au contenu Markdown.

Blague #1 : CSS est le seul langage où l’on peut se tromper de dix-sept façons différentes et quand même livrer une page qui « semble correcte » sur votre laptop.

Faits et contexte historique qui expliquent le désordre actuel

Markdown paraît intemporel, mais son écosystème est un patchwork. Quelques faits rapides expliquent pourquoi vous ne pouvez pas traiter le « styling Markdown » comme une cible unique :

  1. Markdown a commencé comme un format de commodité, pas comme une norme de publication. Le Markdown original de John Gruber (2004) visait à écrire du HTML plus vite, pas à garantir une sortie sémantique cohérente entre implémentations.
  2. CommonMark existe parce que « Markdown » était trop ambigu. Différents parseurs ne s’accordaient pas sur les cas limites (soulignements dans les mots, listes imbriquées), ce qui signifie que votre HTML peut varier selon le renderer.
  3. Le Markdown « flavorisé » de GitHub a popularisé les tableaux et les listes de tâches. Ces fonctionnalités ne faisaient pas partie du spec original mais sont devenues attendues ; votre CSS doit donc les gérer.
  4. La typographie web d’antan supposait des lignes courtes et une faible densité. Beaucoup de valeurs par défaut viennent d’une ère d’écrans 800×600. Aujourd’hui, écrans géants et petits téléphones touchent tous votre contenu.
  5. Les bibliothèques de coloration syntaxique ont influencé les attentes CSS. Outils comme highlight.js et Prism injectent beaucoup de classes (span soup) dans les pre, ce qui affecte hauteur de ligne et sélection.
  6. Les resets CSS ont normalisé les différences entre navigateurs — puis créé de nouveaux conflits. Un reset peut annuler les margin des listes et titres, laissant le contenu Markdown ressemblant à un mur de texte à moins de réintroduire un rythme.
  7. Les tableaux n’ont jamais été mobiles par défaut. Les tableaux HTML précèdent le design responsive ; les wrappers à défilement horizontal sont devenus la solution de contournement courante.
  8. Le dark mode est une exigence moderne, pas un luxe. Une page de doc avec des blocs de code blancs en mode sombre ressemble à une lampe torche. Il faut des couleurs réfléchies.

Un jeu de CSS de base que vous pouvez réellement déployer

Si vous ne retenez qu’une chose de cet article : utilisez une classe conteneur, définissez un rythme typographique et gérez le débordement. Le CSS dans le <style> de ce document est exactement cela : scoped, ennuyeux et résistant aux pannes de contenu courantes.

Voici pourquoi la base est structurée ainsi :

  • Les variables CSS vous offrent un panneau de réglage : changez la pile de polices, les couleurs, les espacements et la longueur de ligne maximale sans chercher dans les sélecteurs.
  • Une largeur maximale en caractères (78ch) garde la longueur de ligne lisible sur tous les écrans. Cela empêche aussi les tableaux et blocs de code de devenir des boules de démolition de mise en page.
  • Le scroll-margin sur les titres empêche les liens ancrés d’être masqués par des headers sticky. Vous vous remercierez la première fois qu’un runbook on-call utilisera des ancres.
  • La classe de wrapper pour tableaux (.table-wrap) permet de contenir le débordement horizontal sans rendre toute la page déroulante latéralement.
  • Les styles d’impression évitent que les blocs de code sombres gaspillent de l’encre et deviennent illisibles.

Ce qu’il ne faut pas faire : copier un stylesheet de « thème blog » avec des layouts grid complexes, des callouts flottants et des pseudo-éléments décoratifs. Le contenu Markdown est un adaptateur universel ; votre CSS doit être un parasurtenseur.

Titres : hiérarchie sans drame

Les titres en Markdown sont sournoisement coûteux. Ils affectent la navigation, le lien d’ancre, la lisibilité et la confiance perçue dans le document. Si les titres paraissent incohérents, le contenu semble incohérent — même si le fond est correct.

Règles d’espacement qui évitent les « docs accordéon »

Mode de défaillance : des titres avec de grandes marges hautes créent un effet « accordéon » où le contenu semble déconnecté et l’utilisateur perd le contexte. L’inverse est pire : des titres sans marge transforment la page en fichier log.

Utilisez une cadence cohérente :

  • h2 reçoit une marge haute plus importante pour clairement séparer les sections.
  • h3 reçoit une marge haute plus petite pour que les sous-sections ne ressemblent pas à des chapitres distincts.
  • Gardez la hauteur de ligne des titres plus serrée que le corps du texte pour éviter les titres sur plusieurs lignes maladroits.

Ancres et headers sticky

Si vous avez un header sticky, le comportement d’ancrage par défaut du navigateur fera défiler le titre sous celui-ci. L’utilisateur clique sur un lien, la page saute, et le titre disparaît. Ce n’est pas seulement agaçant — ça paraît cassé.

Réparez-le avec scroll-margin-top sur les titres. Simple, efficace et sans JavaScript. Choisissez une valeur correspondant à la hauteur de votre header plus un peu de confort.

Ne stylisez pas les titres globalement

Si votre renderer Markdown vit dans une application plus large, les styles globaux de titres sont la manière la plus sûre de restyler accidentellement les titres de modaux, cartes et navigation. Scopez. Toujours.

Listes : espacement, imbrication et pourquoi les puces mentent

Les listes sont l’endroit où le contenu Markdown devient étrange. Listes imbriquées, mix ordered/unordered, listes de tâches et items contenant des paragraphes peuvent produire des variantes de markup selon le renderer.

Espacement qui survit au contenu imbriqué

Les marges par défaut des listes varient selon le navigateur. Les resets suppriment souvent le padding des listes. Résultat : puces collées au bord, ou listes imbriquées qui ressemblent à un escalier posé au milieu de la page.

Règles pratiques :

  • Utilisez padding-left sur ul/ol plutôt que de compter sur les marqueurs par défaut.
  • Donnez à li une petite marge verticale. Pas un plein 1rem, sinon votre liste devient une brochure.
  • Contrôlez explicitement les marges des listes imbriquées pour qu’elles ne gonflent pas.

Listes de tâches et cases à cocher

Certaines implémentations émettent les listes de tâches comme des input type="checkbox" à l’intérieur des li. Si vous stylisez globalement les éléments de formulaire, vous risquez de les redimensionner ou restyler involontairement. Gardez le style des éléments de formulaire Markdown conservateur ou scopez-le strictement.

Blague #2 : les listes imbriquées sont comme des organigrammes — techniquement exactes, émotionnellement épuisantes.

Tableaux : débordement, alignement et la « surprise huit colonnes »

Les tableaux sont la principale cause des plaintes « pourquoi cette page défile horizontalement sur iPhone ? ». Le navigateur élargira volontiers la fenêtre d’affichage pour accommoder un tableau, et votre layout fera une petite danse interprétative.

Entourez les tableaux, ne les combattez pas

Vous avez deux stratégies réalistes :

  1. Autoriser le défilement horizontal. Placez le tableau dans un wrapper avec overflow-x: auto. C’est l’option la moins mauvaise pour des données larges.
  2. Transformer les tableaux en cartes sur petits écrans. C’est séduisant, mais complexe et fragile pour des tableaux Markdown arbitraires. Ne le faites que si vous contrôlez le schéma du tableau.

Pour la plupart du contenu Markdown sauvage, utilisez le wrapper. C’est honnête : les données larges restent larges.

Stabilité : éviter les shifts de layout lors du chargement des tableaux

Les tableaux peuvent provoquer des shifts quand les polices chargent tard ou si la page rend initialement sans les styles de wrapper. Chargez votre CSS critique inline ou tôt, et gardez les styles de tableau simples.

Alignement numérique

Les docs incluent souvent des numéros de version, des tailles et des valeurs de latence. Pensez à font-variant-numeric: tabular-nums sur les tableaux pour réduire le jitter. Ça n’est pas une panacée, mais ça améliore la lisibilité si la police le supporte.

Blocs de code et code inline : lisible, copiable, pas une rançon UX

Le code est l’essence de la plupart des Markdown techniques. Si votre style de code est mauvais, la doc est mauvaise. Point final.

Code inline : lisible sans casser le flux de la ligne

Le code inline doit ressembler à du code, sans crier. Modes de défaillance courants :

  • Le code inline a trop de padding et ressemble à un bouton.
  • Le code inline ne casse pas et provoque un débordement sur mobile à cause de tokens longs.
  • Le code inline utilise une police minuscule qui devient illisible au zoom 125 %.

Utilisez un fond subtil, une bordure fine, un padding modeste et white-space: break-spaces pour permettre aux tokens longs de se casser quand c’est nécessaire.

Blocs de code : le débordement est une fonctionnalité

Ne faites pas wraper les blocs de code par défaut. Le code wrapé casse le copier/coller, masque l’indentation et crée des commandes ambiguës. La bonne option est un défilement horizontal à l’intérieur du bloc (overflow: auto sur pre).

Oui, le défilement horizontal n’est pas « joli ». C’est aussi le comportement des terminaux. Vos utilisateurs s’en accommodent.

Hauteur de ligne et taille de tabulation

Les blocs de code ont besoin d’une hauteur de ligne légèrement plus serrée que la prose, sans être étouffants. Définissez aussi tab-size sur une valeur sensée (2 ou 4). Le rendu par défaut des tabulations varie et peut déformer l’indentation des extraits.

La coloration syntaxique n’améliore pas le contraste

Les librairies de highlighting ajoutent des couleurs, pas de la lisibilité. Commencez par une paire premier-plan/fond à fort contraste, puis superposez les couleurs de surbrillance. En mode sombre, évitez les fonds noirs purs : ils amplifient les halos et rendent la sélection plus difficile à voir.

Citations : encarts sans se transformer en poster motivationnel

Les citations Markdown sont souvent détournées en encarts « note/avertissement ». C’est acceptable, mais votre style doit les garder lisibles et distinctes du texte principal sans dévorer la page.

Utilisez :

  • Une bordure gauche (forte affordance, faible bruit).
  • Une teinte de fond subtile (optionnel, mais utile).
  • Un padding confortable pour que les citations multi-paragraphe ne paraissent pas à l’étroit.

Évitez les guillemets géants, les italiques surdimensionnés ou des changements typographiques dramatiques. Ce n’est pas une invitation de mariage.

Accessibilité et lisibilité : contraste, focus, sélection et mouvement

La documentation est pour tout le monde, y compris la personne qui lit votre runbook d’incident à 3 h du matin, un œil à moitié fermé et la luminosité de l’ordi réglée sur « regret ». L’accessibilité n’est pas de la charité ; c’est de la justesse opérationnelle.

Contraste et choix de couleurs

Les liens doivent être clairement identifiables. Utilisez la soulignement par défaut ou au moins au survol avec un contraste fort. Ne comptez pas uniquement sur la couleur pour différencier le sens à l’intérieur des blocs de code non plus : les couleurs de syntaxe doivent compléter, pas remplacer, le contraste de base.

Couleur de sélection

Les gens copient constamment depuis la doc. Un ::selection personnalisé avec suffisamment de contraste rend le copier moins sujet aux erreurs, surtout dans le code. Gardez-le subtil mais visible.

Contours de focus

Si votre app supprime globalement les outlines de focus, vos liens Markdown deviennent hostiles au clavier. Corrigez cela globalement dans l’app ou restaurez-les à l’intérieur de .md. « Nous supportons la navigation au clavier » est soit vrai soit faux.

Zoom et tailles de polices

N’attribuez pas la taille de police du conteneur Markdown en px puis ne réglez tout le reste qu’en px. Utilisez rem et laissez les utilisateurs zoomer. L’objectif de design est « lisible », pas « identique ».

Performance et stabilité : prévenir les sauts de mise en page et les collisions CSS

La plupart des problèmes CSS se manifestent par « ça a l’air bizarre ». Les plus coûteux apparaissent comme « lent » et « ça saute ». Là où les instincts SRE aident : cherchez les causes systémiques, pas seulement l’esthétique locale.

Prévenir le layout shift (CLS) sur les pages Markdown

Sources communes de layout shift dans le contenu Markdown :

  • Polices qui chargent tard. Le texte se reflowe quand la police est appliquée.
  • Images sans dimensions. La page se contracte puis s’étend quand l’image arrive.
  • Tableaux et blocs de code qui s’étendent après le rendu. Si votre CSS arrive tard, le rendu initial peut être non stylé.

Atténuations pratiques :

  • Privilégiez des piles de polices système pour la doc, ou préchargez la police que vous utilisez.
  • Assurez-vous que votre pipeline Markdown ajoute width et height pour les images quand c’est possible, ou utilisez des patterns CSS aspect-ratio si vous contrôlez la sortie.
  • Inlinez le CSS critique minimal pour .md (espacements, blocs de code, tableaux) pour que le premier rendu soit stable.

Collisions CSS : pourquoi le scoping est non négociable

La sortie Markdown est du HTML : titres, listes, tableaux, pre, code, blockquote. Votre application stylise probablement déjà ces éléments globalement. Si vous ne scopez pas les styles Markdown, vous allez soit :

  • Casser les composants UI de l’app avec des styles « doc », ou
  • Casser les docs en héritant de styles de composants que vous ne destiniez pas au contenu.

Scopez via une classe conteneur. Si vous voulez plus de sécurité, utilisez des layers de cascade et gardez le Markdown dans une couche de priorité inférieure à vos composants système — ou l’inverse selon la règle de droit de votre produit. Mais choisissez une approche et appliquez-la.

Playbook de diagnostic rapide

Quand on signale « la page Markdown est cassée », il faut isoler le goulot vite : rendu, collisions CSS, débordement ou performance. Voici l’ordre qui fait gagner du temps.

Première étape : isoler la portée et les collisions

  • Inspectez l’élément conteneur Markdown. Vérifiez qu’il a une classe de scope dédiée (comme .md).
  • Dans DevTools, vérifiez les styles calculés pour h2, ul, pre, table. Si les styles proviennent d’un reset global ou d’une librairie de composants, vous avez une collision.
  • Désactivez temporairement les styles typographiques/reset globaux pour voir si le Markdown redevient raisonnable. Si oui : corrigez le scoping et l’ordre de cascade.

Deuxième étape : identifier le coupable du débordement

  • Recherchez un défilement horizontal sur la page. Trouvez quel élément dépasse la fenêtre.
  • Coupables fréquents : table, pre, chaînes longues sans coupure dans les paragraphes, images à largeur fixe.
  • Ajoutez un confinement : entourez les tableaux, placez overflow: auto sur les blocs de code et appliquez des règles de césure seulement à la prose — pas aux blocs de code.

Troisième étape : vérifier la performance et les layout shifts

  • Mesurez le CLS et le comportement de swap des polices. Si la page saute, le CSS ou les polices arrivent tard.
  • Vérifiez que les images ont des dimensions. Sinon, corrigez au niveau du pipeline Markdown.
  • Confirmez que la coloration syntaxique ne fait pas de travail DOM lourd à chaque rendu.

Tâches pratiques : commandes, sorties et décisions suivantes

Voici les tâches que j’exécute réellement quand un problème de styling de page docs frappe la production. Elles ciblent le pipeline : artefacts de build, payload CSS, caching et régressions. Chaque tâche inclut une commande, une sortie d’exemple et la décision qui en découle.

Task 1: Verify the Markdown HTML output is what you think it is

cr0x@server:~$ node -e "const fs=require('fs');const md=fs.readFileSync('sample.md','utf8');const {marked}=require('marked');console.log(marked.parse(md).slice(0,800));"
<h1>Runbook: Database failover</h1>
<p>If replication is behind, stop and verify.</p>
<h2>Prereqs</h2>
<ul>
<li>Access to <code>prod-bastion</code></li>
<li>Current primary is <code>db-01</code></li>
</ul>
<pre><code class="language-bash">...</code></pre>

Ce que cela signifie : Vous confirmez si votre renderer émet <pre><code> avec des classes, comment les listes sont imbriquées et si des tableaux existent.

Décision : Si la sortie diffère entre environnements (serveur vs client), stoppez. Alignez le renderer ou normalisez la sortie avant de toucher au CSS.

Task 2: Check which CSS rules win (collision audit)

cr0x@server:~$ rg -n "pre\\s*\\{|code\\s*\\{|table\\s*\\{|blockquote\\s*\\{|h2\\s*\\{" dist/assets/*.css | head
dist/assets/app.4f19c8.css:231:pre{white-space:pre-wrap;word-break:break-word}
dist/assets/app.4f19c8.css:877:table{width:100%;font-size:12px}
dist/assets/docs.8a02b1.css:44:.md pre{overflow:auto;background:#0b1220}
dist/assets/docs.8a02b1.css:71:.md table{border-collapse:collapse}

Ce que cela signifie : Vous voyez des règles globales comme pre{white-space:pre-wrap} qui peuvent casser les blocs de code.

Décision : Déplacez les styles Markdown dans un fichier scoped chargé après le reset, ou changez le reset pour éviter d’affecter pre globalement.

Task 3: Measure CSS payload size (docs styles should be lean)

cr0x@server:~$ ls -lh dist/assets/*css | sed -n '1,10p'
-rw-r--r-- 1 cr0x cr0x 412K Dec 29 11:20 dist/assets/app.4f19c8.css
-rw-r--r-- 1 cr0x cr0x  18K Dec 29 11:20 dist/assets/docs.8a02b1.css

Ce que cela signifie : Le CSS docs est séparé et petit. Bien. S’il est gigantesque, vous importez probablement tout votre design system pour une page runbook.

Décision : Si le CSS docs est gonflé, scindez les bundles ou inlinez seulement les styles critiques pour la doc.

Task 4: Confirm gzip/brotli is active for CSS

cr0x@server:~$ curl -sI -H 'Accept-Encoding: br' http://localhost:8080/assets/docs.8a02b1.css | sed -n '1,12p'
HTTP/1.1 200 OK
Content-Type: text/css; charset=utf-8
Content-Encoding: br
Cache-Control: public, max-age=31536000, immutable
Vary: Accept-Encoding
ETag: "8a02b1"

Ce que cela signifie : La compression est active, le caching est immutable et le serveur varie selon l’encodage. C’est le baseline pour une livraison rapide des docs.

Décision : Si la compression manque, corrigez la config serveur avant d’optimiser les selecteurs.

Task 5: Verify caching headers for rendered Markdown pages

cr0x@server:~$ curl -sI http://localhost:8080/docs/runbook/db-failover | sed -n '1,14p'
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: no-store
Vary: Accept-Encoding

Ce que cela signifie : La page n’est pas mise en cache. Ça peut être correct pour des runbooks authentifiés, ou accidentel.

Décision : Si le contenu est statique et public, vous voulez du caching. S’il est privé ou par utilisateur, conservez no-store mais assurez-vous que les assets sont massivement mis en cache.

Task 6: Find which element causes horizontal scrolling

cr0x@server:~$ node -e "console.log('Use DevTools: run in console: [...document.querySelectorAll(\"body *\")].filter(e=>e.scrollWidth>e.clientWidth).slice(0,5).map(e=>[e.tagName,e.className,e.scrollWidth-e.clientWidth]) )')"
Use DevTools: run in console: [...document.querySelectorAll("body *")].filter(e=>e.scrollWidth>e.clientWidth).slice(0,5).map(e=>[e.tagName,e.className,e.scrollWidth-e.clientWidth])

Ce que cela signifie : Vous utilisez une méthode fiable pour trouver les éléments débordants plutôt que de deviner.

Décision : Si les coupables sont TABLE ou PRE, ajoutez des wrappers/overflow. Si ce sont des paragraphes, appliquez des règles de césure sûres pour la prose.

Task 7: Detect unbroken strings in Markdown that will overflow

cr0x@server:~$ perl -ne 'while(/(\S{80,})/g){print "$ARGV:$.:$1\n"}' docs/**/*.md | head
docs/runbook/net-debug.md:42:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
docs/howto/api.md:118:sha256:8c3d0f0a1c7b9d2e4f6a9b1c3d5e7f9a0b2c4d6e8f0a2b4c6d8e0f2a4c6d8e0f2

Ce que cela signifie : Vous avez trouvé des tokens qui casseront la mise en page si vous n’autorisez pas la coupure en prose.

Décision : Ajoutez overflow-wrap: anywhere sur .md p si nécessaire, mais ne l’appliquez pas aux pre/code.

Task 8: Confirm code blocks aren’t being wrapped by a reset

cr0x@server:~$ rg -n "pre\\s*\\{[^}]*white-space:\\s*pre-wrap" dist/assets/app.*.css
dist/assets/app.4f19c8.css:231:pre{white-space:pre-wrap;word-break:break-word}

Ce que cela signifie : Le reset force le wrapping et casse les codes sensibles à l’indentation.

Décision : Surchargez à l’intérieur de .md avec .md pre{white-space:pre;} et supprimez la règle globale si possible.

Task 9: Validate that Markdown headings have stable anchor IDs

cr0x@server:~$ node -e "const s=require('fs').readFileSync('sample.html','utf8');const ids=[...s.matchAll(/id=\"([^\"]+)\"/g)].map(m=>m[1]);console.log(ids.filter(x=>x.includes(' ')).slice(0,10));"
[]

Ce que cela signifie : Pas d’IDs avec des espaces. Bien. Les IDs d’ancre avec des caractères non sûrs cassent souvent les TOC et les liens profonds.

Décision : Si les IDs sont instables, corrigez la génération de slug dans le renderer plutôt que de bricoler du CSS.

Task 10: Ensure tables are wrapped (if your renderer supports post-processing)

cr0x@server:~$ node -e "const {JSDOM}=require('jsdom');const fs=require('fs');const html=fs.readFileSync('sample.html','utf8');const dom=new JSDOM(html);const d=dom.window.document;d.querySelectorAll('.md table').forEach(t=>{const w=d.createElement('div');w.className='table-wrap';t.parentNode.insertBefore(w,t);w.appendChild(t);});console.log(d.querySelectorAll('.table-wrap table').length);"
3

Ce que cela signifie : Vous pouvez appliquer un wrapper même si les auteurs n’y pensent pas.

Décision : Si les tableaux débordent régulièrement, faites le wrapping automatiquement dans le pipeline. Ne comptez pas sur la discipline des auteurs.

Task 11: Check if your syntax highlighter bloats the DOM

cr0x@server:~$ node -e "const fs=require('fs');const html=fs.readFileSync('sample.html','utf8');const spans=(html.match(/

Ce que cela signifie : Le highlighting a injecté beaucoup de spans. Ça peut impacter la performance, surtout sur des appareils bas de gamme.

Décision : Si le nombre de spans est énorme, envisagez du highlighting côté serveur pour la doc statique, limitez les langages mis en évidence, ou utilisez des thèmes plus légers.

Task 12: Inspect Lighthouse-like signals for layout shift in CI (quick and dirty)

cr0x@server:~$ node -e "console.log('Run a headless audit in CI (example): npx playwright test --project=chromium; capture CLS via PerformanceObserver and fail if above threshold')"
Run a headless audit in CI (example): npx playwright test --project=chromium; capture CLS via PerformanceObserver and fail if above threshold

Ce que cela signifie : Vous transformez « quelqu’un a remarqué que ça saute » en un test de régression.

Décision : Si le CLS régresse, traitez-le comme une dette de performance : corrigez les polices, les dimensions d’images ou l’ordre de chargement du CSS.

Task 13: Confirm fonts are not blocking rendering

cr0x@server:~$ rg -n "@font-face" dist/assets/*.css | head
dist/assets/app.4f19c8.css:12:@font-face{font-family:Inter;src:url(/assets/Inter.woff2) format("woff2");font-display:swap}

Ce que cela signifie : font-display: swap est défini, réduisant le FOIT (flash of invisible text).

Décision : Si swap manque et que vous observez du texte invisible, ajoutez-le. Ou utilisez une pile de polices système pour les pages Markdown.

Task 14: Validate CSS scoping is enforced (no global tag selectors in docs CSS)

cr0x@server:~$ awk 'length($0)<500{print}' dist/assets/docs.8a02b1.css | rg -n "^(h1|h2|h3|p|pre|code|table|ul|ol|blockquote)\b" | head

Ce que cela signifie : Pas de correspondances : la feuille de style docs ne contient pas de sélecteurs de balises brutes au niveau supérieur.

Décision : Si vous voyez des sélecteurs globaux, refactorez-les en .md h2 etc. Ne négociez pas avec de futures pannes.

Erreurs fréquentes : symptômes → cause racine → correction

1) Symptom: code blocks wrap and commands become uncopyable

Cause racine : Un reset global définit pre { white-space: pre-wrap; word-break: break-word; } ou applique word-break à tous les code.

Correction : À l’intérieur du scope Markdown, définissez explicitement .md pre { overflow:auto; } et .md pre code { white-space: pre; }. Supprimez les règles globales si vous le pouvez.

2) Symptom: mobile page has horizontal scrolling even with no tables

Cause racine : Tokens non cassés dans la prose (hashes, URLs longues, blobs base64) combinés à white-space: nowrap hérité d’un style de composant.

Correction : Définissez .md p { overflow-wrap: anywhere; } ou word-break: break-word; pour la prose seulement. Gardez les blocs de code en white-space: pre.

3) Symptom: lists look like one dense paragraph

Cause racine : Le reset CSS a retiré les marges/paddings des listes ; aucun rythme de remplacement fourni.

Correction : Restaurez le padding et les marges des listes à l’intérieur de .md. Ajoutez de petites marges verticales aux li et contrôlez l’espacement des listes imbriquées.

4) Symptom: tables blow out the layout or shrink to unreadable text

Cause racine : Largeur de tableau forcée à 100% plus une petite taille de police globale, ou tableaux non entourés pour le débordement.

Correction : Entourez les tableaux avec overflow-x:auto. Gardez la taille de police au niveau de base. Si nécessaire, autorisez un min-width sur les colonnes ou comptez sur le défilement horizontal.

5) Symptom: headings overlap sticky header when using anchors

Cause racine : Aucun comportement d’offset de scroll configuré.

Correction : Ajoutez scroll-margin-top aux titres dans le scope Markdown. Utilisez une valeur alignée sur la hauteur du header.

6) Symptom: inline code looks like clickable buttons and distracts

Cause racine : code sur-stylé avec padding important, fond saturé et contraste élevé.

Correction : Réduisez le padding, utilisez un fond subtil et une bordure fine, et gardez la taille de police proche de celle du corps.

7) Symptom: dark mode docs are unreadable (either too dim or too bright)

Cause racine : Couleurs choisies pour le mode clair inversées maladroitement ; blocs de code restent clairs ou utilisent du noir pur.

Correction : Définissez des variables séparées pour le mode sombre. Utilisez des fonds bleu-nuit plutôt que du noir pur, et conservez des couleurs de lien lisibles.

8) Symptom: “why did this doc page change the styling of our checkout page?”

Cause racine : La feuille de style Markdown utilise des sélecteurs de balises globaux (h2 { ... }, table { ... }) livrés sur toutes les pages.

Correction : Scopez tout sous une classe conteneur ; chargez le CSS docs uniquement où c’est nécessaire ; considérez les layers de cascade.

Trois mini-histoires d’entreprise venues des tranchées Markdown

Incident causé par une mauvaise hypothèse : « Notre renderer Markdown produit toujours le même HTML »

Une entreprise pour laquelle j’ai travaillé avait deux chemins de rendu Markdown : côté serveur pour la doc publique, côté client pour les runbooks internes. C’était parti comme optimisation : les pages internes rendaient plus vite après navigation, et l’équipe portail interne pouvait itérer sans redéployer le backend.

Tout le monde supposait « Markdown c’est Markdown », donc le HTML serait identique. Ce n’était pas le cas. Le renderer serveur produisait <pre><code class="language-bash">. Le renderer client produisait <pre class="language-bash"><code>. Le CSS, naturellement, ciblait une seule de ces formes.

La défaillance est apparue pendant un incident : un ingénieur on-call a collé une commande depuis un runbook, mais le bloc de code s’était wrapé au milieu d’un flag à cause d’une règle globale sur pre. La commande collée échoua. L’ingénieur a retenté avec des modifications, puis a cessé de faire confiance au runbook et a commencé à improviser. Le temps a dérapé.

La cause racine du postmortem n’était pas « mauvais CSS », mais « deux renderers, un seul modèle mental ». La correction fut double : normaliser la sortie Markdown (choisir un renderer ou post-traiter pour obtenir une forme HTML canonique) et scopez le CSS des blocs de code pour gérer les deux formes. Ensuite ils ont ajouté un test qui rendait le même Markdown via les deux chemins et diffait le DOM pour les nœuds clés.

Optimisation qui s’est retournée contre eux : « Réduisons le DOM en supprimant les wrappers »

Une autre équipe voulait accélérer les pages docs en simplifiant le HTML généré. Ils ont retiré les wrappers autour des tableaux et blocs de code parce que « les div en trop sont mauvaises ». Philosophiquement propre. Opérationnellement chaotique.

Sans wrapper de tableau, la seule manière d’empêcher un tableau large de casser la mise en page était d’appliquer des règles d’overflow directement au tableau ou à son parent. Mais l’overflow ne fonctionne pas sur les tableaux comme on le souhaite, et le parent contenait aussi du texte normal. Soudain, toute la page avait un comportement de défilement horizontal parce qu’un tableau était large.

Ils ont alors « optimisé » davantage en ajoutant word-break: break-all sur le conteneur Markdown pour éviter le débordement. Cela a stoppé le scrolling, mais aussi cassé le copier/coller des hashes, URLs et code inline. Les on-call ont commencé à recevoir des tickets du type « vos docs corrompent les commandes ». Ce qui est particulièrement embarrassant car le contenu était correct ; c’était le CSS qui mentait.

Ils ont finalement réintroduit des wrappers pour tableaux et blocs de code, mais de manière contrôlée : le renderer ajoute des wrappers seulement quand c’est nécessaire (table présent, code présent). La page redevint stable et le gain de performance lié à la suppression des wrappers s’est avéré surtout imaginaire comparé au coût des reflows et autres problèmes.

Pratique ennuyeuse mais correcte qui a sauvé la mise : « Nous snapshotons les styles docs et testons les cas pourris »

Une organisation que je respecte traitait les styles docs comme une API. Ils avaient un petit jeu de fixtures « Markdown maléfique » : listes profondément imbriquées, tokens longs, tableaux larges, code inline mixte, citations contenant des listes, images et un bloc de code avec une longue ligne de commande.

Chaque changement à la typographie passait par des snapshots visuels en CI à trois largeurs de viewport et deux thèmes colorés. Ce n’était pas glamour. Personne n’a été promu pour « réduction de 2px de marge sur li ». Mais ça a empêché des régressions qui auraient frappé le public le plus critique : des personnes en train de faire leur travail.

Pendant une refonte, un reset global est arrivé qui a retiré toute indentation de liste et a transformé pre en wrapping. Les fixtures l’ont détecté avant la release. La correction a été une surcharge scoped dans .md et une règle : les resets globaux ne peuvent pas affecter les balises HTML brutes sans l’accord d’un propriétaire du design system.

La pratique ennuyeuse — fixtures, snapshots, CSS scoped — a permis à la refonte de sortir sans que la doc devienne un dommage collatéral. Voilà à quoi ressemble la « fiabilité » quand le système est principalement du texte.

Checklists / plan étape par étape

Plan étape par étape pour implémenter un CSS Markdown sensé

  1. Introduisez une classe conteneur Markdown. Enveloppez tout le Markdown rendu dans <div class="md">...</div>. Aucune exception.
  2. Définissez des variables pour la typographie et l’espacement. Fixez la pile de polices de base, la couleur du texte, la couleur des liens, les bordures et l’échelle d’espacement.
  3. Restaurez le rythme typographique. Définissez les marges pour p, h2, h3 et les listes à l’intérieur de .md.
  4. Renforcez le comportement de débordement. Blocs de code : overflow:auto. Tableaux : wrapper scroll. Prose : permettre la coupure des tokens longs.
  5. Faites fonctionner les ancres. Ajoutez scroll-margin-top aux titres et assurez la stabilité des IDs.
  6. Gérez le dark mode délibérément. Utilisez des variables CSS avec des overrides prefers-color-scheme: dark.
  7. Ajoutez des styles d’impression. Surtout pour les blocs de code et les liens.
  8. Créez des fixtures Markdown. Incluez des exemples pires cas. Gardez-le petit mais méchant.
  9. Automatisez la vérification. Tests de snapshot et un détecteur simple d’overflow. Faites échouer les builds sur régressions.
  10. Déployez le CSS scoped uniquement où nécessaire. Si la doc est sur une route dédiée, ne chargez pas la feuille Markdown partout.

Checklist pré-flight pour un changement de style Markdown

  • Le changement n’affecte-t-il que le scope .md ?
  • Avez-vous testé un tableau large sur un viewport étroit ?
  • Avez-vous testé un token long non coupé dans un paragraphe ?
  • Une longue ligne de code reste-t-elle copiable ?
  • Les liens d’ancre arrivent-ils correctement sous un header sticky ?
  • Le mode sombre conserve-t-il le contraste pour les liens et le code ?
  • L’impression produit-elle des blocs de code lisibles ?

Checklist de rollback

  • Pouvez-vous désactiver le nouveau CSS docs via un feature flag ou une config route-level ?
  • Avez-vous un stylesheet artifact connu-good à redéployer rapidement ?
  • Avez-vous un style « safe mode » minimal (polices système, espacements basiques, règles d’overflow) pour revenir en arrière ?

FAQ

1) Dois-je utiliser un reset CSS pour le contenu Markdown ?

Pas directement. Utilisez un reset au niveau application si besoin, mais rebâtissez explicitement l’espacement et la typographie à l’intérieur de .md. La doc a besoin de marges ; des docs à zéro marge sont hostiles.

2) Est-ce acceptable de wraper les blocs de code au lieu de les faire défiler ?

Seulement si vous acceptez des copier/coller cassés et une indentation ambiguë. Pour les runbooks et commandes, privilégiez le défilement horizontal. Si vous avez besoin du wrapping pour du code de type prose (rare), rendez-le optionnel.

3) Comment rendre des tableaux responsives sans scroll horizontal ?

Vous pouvez transformer les lignes en cartes avec du CSS, mais cela suppose que vous connaissez le schéma. Pour des tableaux Markdown arbitraires, le scroll horizontal est le comportement le plus fiable.

4) Pourquoi mon Markdown a-t-il l’air différent entre environnements ?

Différents renderers Markdown (ou versions différentes) produisent des structures HTML différentes. Corrigez l’alignement des renderers d’abord. Le CSS peut camoufler des différences mais vous courrez après des cas limites sans fin.

5) Ai-je besoin de styles séparés pour le Markdown rendu côté serveur et côté client ?

Vous avez besoin de styles qui correspondent au HTML émis. La meilleure solution est de rendre le HTML émis cohérent entre chemins de rendu, puis d’écrire une seule feuille scoped.

6) Comment empêcher les styles Markdown d’affecter le reste de l’app ?

Scopez avec une classe conteneur et évitez les sélecteurs de balises globaux. Envisagez aussi de charger le CSS docs seulement sur les routes docs. « On fera attention » n’est pas une stratégie.

7) Que faire des thèmes de coloration syntaxique — en choisir un et c’est tout ?

Choisissez un thème avec un bon contraste qui ne repose pas sur des tailles de police minuscules. Vérifiez ensuite la visibilité lors de la sélection et le copier/coller. Une coloration jolie mais illisible en mode sombre est une régression.

8) Le contenu Markdown doit-il utiliser la même typographie que l’UI produit ?

Généralement oui pour le texte courant, mais les blocs de code doivent toujours utiliser une pile monospace solide. Gardez la doc familière, mais ne forcez pas des contraintes UI qui nuisent à la lisibilité (cartes étroites, polices minuscules).

9) Puis-je simplement utiliser une bibliothèque « Markdown CSS » populaire ?

Vous pouvez, mais traitez-la comme du code tiers : auditez-la, scopez-la et testez vos pires contenus. Beaucoup de bibliothèques supposent des billets de blog, pas des runbooks.

10) Quel est le CSS minimum nécessaire pour un rendu Markdown acceptable ?

Marges scoped pour titres/paragraphes/listes, style d’overflow pour blocs de code, wrapper de tableau et style de lien. Le reste est qualité de vie.

Conclusion : prochaines étapes réalisables cette semaine

Le styling Markdown devient « difficile » quand vous le traitez comme décoratif. Traitez-le comme une interface de production : entrée semi-fiable, sortie variable et des utilisateurs réels qui en dépendent pour travailler.

Faites ceci ensuite :

  1. Enveloppez le Markdown rendu dans un scope dédié et arrêtez de styliser les balises brutes globalement.
  2. Implémentez la base : espacement cohérent pour titres/listes, overflow des blocs de code et wrappers de tableau.
  3. Construisez un petit jeu de fixtures de Markdown moche et faites des snapshots à plusieurs viewports et thèmes.
  4. Ajoutez un détecteur d’overflow rapide et un garde-fou CLS en CI pour que « ça a l’air bon sur ma machine » cesse d’être votre plan QA.

Quand vos docs sont stables, vos on-call vont plus vite, l’onboarding s’améliore et l’équipe UI cesse de considérer Markdown comme un sous-système rebelle. C’est une vraie victoire de fiabilité — faite de texte.

← Précédent
Pourquoi les benchmarks synthétiques mentent (et comment les démasquer)
Suivant →
Ventilateurs installés à l’envers : quand le flux d’air prend la mauvaise direction

Laisser un commentaire