Jour 47 Day 47 · mercredi 14 octobre 2026 Wednesday 14 October 2026 Web Fondamental
CSS moderne & accessibilité Modern CSS & accessibility
Spécificité, flexbox vs grid, unités modernes, et l'accessibilité qui commence par le HTML : les fondamentaux front que les recruteurs vérifient en cinq questions. Specificity, flexbox vs grid, modern units, and accessibility that starts with HTML: the front-end fundamentals recruiters check in five questions.
L’essentiel
CSS a mûri : là où il fallait des hacks (floats pour la mise en page, JS pour centrer), le langage offre aujourd’hui des outils natifs — flexbox, grid, custom properties, clamp(). Ce qui n’a pas changé : la cascade et la spécificité, le cœur du langage, que la plupart des bugs CSS « mystérieux » révèlent mal compris.
L’accessibilité (a11y) n’est pas une couche cosmétique ajoutée à la fin : elle commence par le HTML sémantique. Un <button> natif apporte gratuitement le focus clavier, le rôle annoncé aux lecteurs d’écran, l’activation Entrée/Espace ; un <div onclick> n’apporte rien de tout ça. En entretien front, ces deux sujets tombent systématiquement — et distinguent celui qui « fait du CSS » de celui qui le comprend.
La spécificité, le vrai calcul : un triplet (id, classes, éléments) comparé de gauche à droite — pas une somme magique :
Spécificité = (id, classes/attributs/pseudo-classes,
éléments/pseudo-éléments)
style="…" → inline : au-dessus de tout
#nav .link:hover → (1, 2, 0)
.menu .link → (0, 2, 0)
a.link → (0, 1, 1)
nav a → (0, 0, 2)
(1,0,0) bat (0,15,3) : un id bat n'importe quel
nombre de classes. À égalité : la dernière règle
déclarée gagne. !important court-circuite tout.
Comment ça marche
La cascade résout chaque conflit dans cet ordre : origine et importance (styles navigateur < feuille auteur < !important), couches (@layer), spécificité, et enfin ordre d’apparition. !important gagne contre tout — c’est pour ça que c’est un aveu : on l’utilise quand on a perdu le contrôle de sa spécificité, et il déclenche la surenchère (le prochain conflit exigera un autre !important). La solution durable : rester bas et homogène en spécificité (des classes, pas d’id dans les sélecteurs), pour pouvoir toujours surcharger simplement.
Flexbox vs Grid : une dimension contre deux.
| Flexbox | Grid | |
|---|---|---|
| Dimension | 1D : une ligne OU une colonne | 2D : lignes ET colonnes ensemble |
| Qui pilote | Le contenu (les items se répartissent) | Le conteneur (la grille est définie) |
| Cas typiques | navbar, groupe de boutons, centrage | layout de page, galerie, dashboard |
| Retour à la ligne | flex-wrap, rangées indépendantes | alignement 2D cohérent |
| Le duo gagnant | L’intérieur des composants | La structure de la page |
Les deux se combinent : grid pour le squelette de la page, flexbox à l’intérieur des composants. Et le centrage, question piège favorite : display: grid; place-items: center; sur le parent — deux lignes.
Unités et outils modernes :
rem(relative à la racine) pour le texte : respecte le réglage de taille de l’utilisateur — contrairement aupxfigé. C’est un enjeu d’accessibilité, pas de style.clamp(min, préféré, max): la typo fluide sans media query —font-size: clamp(1rem, 2.5vw, 1.5rem).dvh(dynamic viewport height) : corrige le bug classique du100vhsur mobile, où la barre d’URL masque le bas de page.- Custom properties (
--accent: #0057b8) : de vraies variables vivantes dans la cascade, surchargeables par contexte (thème sombre, composant) — ce que les variables Sass, compilées puis figées, ne savent pas faire. - Container queries (en survol) :
@containeradapte un composant à la taille de son conteneur, pas de l’écran. Le chaînon manquant du responsive par composant : une card réutilisée dans une sidebar étroite ou une zone large s’adapte seule.
Mobile-first : les styles de base ciblent le petit écran, puis les @media (min-width: …) enrichissent en montant. Plus simple à raisonner — on ajoute au lieu d’annuler — et aligné sur la réalité du trafic.
Concepts clés à maîtriser
L’accessibilité, dans l’ordre d’importance :
- HTML sémantique d’abord :
<button>,<a>,<nav>,<main>,<label>relié à son input. L’essentiel de l’accessibilité est gratuit quand les bons éléments sont utilisés. - Alternatives textuelles :
altdescriptif sur les images informatives ;alt=""(vide, pas absent) sur les décoratives, pour que les lecteurs d’écran les sautent au lieu de lire le nom du fichier. - Contraste : 4.5:1 minimum pour le texte normal (WCAG AA), 3:1 pour le grand texte. Vérifiable en deux clics (DevTools, WebAIM).
- Focus visible :
:focus-visibleaffiche un contour net à la navigation clavier sans polluer le clic souris. Supprimer l’outline sans remplacement rend le site inutilisable au clavier. - Navigation clavier : tout ce qui se clique doit être atteignable (Tab) et activable (Entrée/Espace). Test à coût zéro : lâcher la souris cinq minutes et traverser sa page.
- ARIA en dernier recours : pour les états que le HTML ne sait pas exprimer (
aria-expanded,aria-live). La première règle d’ARIA, écrite noir sur blanc par le W3C : ne pas utiliser ARIA quand un élément natif suffit.
Un composant accessible, au complet :
<!-- Un vrai <button> : focus, rôle, clavier — tout est natif -->
<button class="menu-btn" aria-expanded="false" aria-controls="menu">
Menu
</button>
<ul id="menu" hidden>…</ul>
<style>
.menu-btn {
font-size: 1rem; /* rem : suit le réglage utilisateur */
padding: 0.5em 1em; /* em : suit la taille du texte */
cursor: pointer;
}
.menu-btn:focus-visible { /* visible au clavier, pas au clic */
outline: 3px solid var(--accent, #0057b8);
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { /* respecte le réglage système */
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
</style>
Le seul ARIA nécessaire ici : aria-expanded (l’état ouvert/fermé, que le HTML ne sait pas exprimer) et aria-controls (le lien vers le menu). Le JS bascule aria-expanded et hidden — c’est tout.
⚠️ Le div cliquable —
<div onClick={...}>est le péché originel du front moderne : pas de focus (invisible au Tab), pas de rôle (muet pour les lecteurs d’écran), pas d’activation clavier (Entrée/Espace ignorés), pas d’état:disabled. Le rendre accessible exigetabindex="0",role="button", un handlerkeydown… soit réimplémenter, mal, ce que<button>donne en une balise. Si ça se clique :<button>pour une action,<a>pour une navigation.
💡 prefers-reduced-motion — certains utilisateurs (troubles vestibulaires, sensibilité au mouvement) désactivent les animations dans leur OS. Le réglage arrive en CSS via
@media (prefers-reduced-motion: reduce): le respecter coûte cinq lignes, l’ignorer rend le site physiquement pénible. Le mentionner en entretien signale une culture a11y au-dessus de la moyenne.
En entretien
« C’est quoi la spécificité CSS ? » — Le mécanisme qui départage deux règles ciblant le même élément : un triplet (id, classes/pseudo-classes/attributs, éléments) comparé position par position, de gauche à droite. Un id bat n’importe quel nombre de classes ; à égalité exacte, la dernière règle déclarée gagne ; le style inline surclasse le tout, et !important court-circuite le mécanisme. Bonne pratique : rester bas et homogène (des classes) pour garder la main sur les surcharges.
« Flexbox ou Grid : comment tu choisis ? » — Une dimension → flexbox : navbar, ligne de boutons, les items se répartissent le long d’un axe. Deux dimensions → grid : layout de page, galerie, lignes et colonnes définies ensemble. Ils se combinent : grid pour la structure, flexbox dans les composants. Bonus : place-items: center sur un parent grid centre un élément en deux lignes.
« Pourquoi un <button> plutôt qu’un <div> cliquable ? » — Le natif apporte gratuitement : focus clavier, rôle annoncé aux lecteurs d’écran, activation Entrée/Espace, état :disabled, comportement dans les formulaires. Le div exige de tout réimplémenter (tabindex, role, keydown) et le résultat est toujours incomplet. La règle : ARIA et JS ne réparent pas un mauvais HTML.
« Comment tu rends un site responsive ? » — Mobile-first : styles de base pour petit écran, media queries min-width pour enrichir. Layouts fluides avec grid/flexbox (minmax(), auto-fit), typo fluide avec clamp(), images en max-width: 100%. Et pour les composants réutilisés dans des contextes de largeurs différentes : container queries.
« C’est quoi ARIA, et quand l’utiliser ? » — Des attributs qui décrivent rôles et états aux technologies d’assistance quand le HTML natif ne suffit pas : aria-expanded pour un menu déroulant, aria-live pour du contenu mis à jour dynamiquement. Première règle d’ARIA : préférer l’élément natif. Et un mauvais ARIA est pire que pas d’ARIA : il promet aux lecteurs d’écran des comportements que le JS n’assure pas.
Pièges & idées reçues
!importantpour « régler » un conflit : il le masque et déclenche la surenchère — le prochain conflit exigera un!importantde plus. Le vrai fix : comprendre quelle règle gagne et pourquoi, puis baisser la spécificité.- « L’accessibilité, c’est pour la fin du projet » : rattraper l’a11y sur du mauvais HTML coûte dix fois le prix de partir des bons éléments. Et le public concerné est large : handicaps permanents, temporaires (bras cassé) et situationnels (plein soleil, bébé dans un bras).
outline: nonesans remplacement : le classique du « c’est moche » qui rend le site inutilisable au clavier.:focus-visiblerègle l’esthétique proprement : contour au clavier, rien au clic.- ARIA partout :
role="button"sur un<button>,aria-labelredondants… Le sur-ARIA dégrade l’expérience au lecteur d’écran. La doc du W3C le dit littéralement : no ARIA is better than bad ARIA. pxpour les tailles de texte : ignore le réglage de l’utilisateur qui a agrandi sa police système.rempour le texte, toujours.- Tester uniquement à la souris sur son écran : cinq minutes au clavier + un test de contraste attrapent la moitié des problèmes d’accessibilité avant la review.
Pour aller plus loin
- MDN — Specificity et Introducing the CSS Cascade
- CSS-Tricks — A Complete Guide to Flexbox et A Complete Guide to CSS Grid
- web.dev — Learn CSS et Learn Accessibility — les deux parcours gratuits de Google
- The A11Y Project — checklist d’accessibilité pragmatique
- WebAIM — Contrast Checker — vérifier un contraste en deux secondes
- W3C — Using ARIA : the first rule of ARIA
The essentials
CSS has matured: where hacks were once required (floats for layout, JS for centering), the language now offers native tools — flexbox, grid, custom properties, clamp(). What hasn’t changed: the cascade and specificity, the core of the language, which most “mysterious” CSS bugs reveal to be misunderstood.
Accessibility (a11y) is not a cosmetic layer added at the end: it starts with semantic HTML. A native <button> gives you keyboard focus, a role announced to screen readers, and Enter/Space activation for free; a <div onclick> gives you none of that. In front-end interviews, both topics come up systematically — and they separate whoever “does CSS” from whoever understands it.
Specificity, the real calculation: a triplet (id, classes, elements) compared left to right — not some magic sum:
Specificity = (id, classes/attributes/pseudo-classes,
elements/pseudo-elements)
style="…" → inline: above everything
#nav .link:hover → (1, 2, 0)
.menu .link → (0, 2, 0)
a.link → (0, 1, 1)
nav a → (0, 0, 2)
(1,0,0) beats (0,15,3): one id beats any number
of classes. On an exact tie: the last declared
rule wins. !important short-circuits it all.
How it works
The cascade resolves each conflict in this order: origin and importance (browser styles < author stylesheet < !important), layers (@layer), specificity, and finally order of appearance. !important beats everything — that’s why it’s a confession: you use it when you’ve lost control of your specificity, and it triggers an arms race (the next conflict will require yet another !important). The durable solution: keep specificity low and homogeneous (classes, no ids in selectors), so you can always override simply.
Flexbox vs Grid: one dimension versus two.
| Flexbox | Grid | |
|---|---|---|
| Dimension | 1D: a row OR a column | 2D: rows AND columns together |
| Who drives | The content (items distribute themselves) | The container (the grid is defined) |
| Typical cases | navbar, button group, centering | page layout, gallery, dashboard |
| Wrapping | flex-wrap, independent rows | consistent 2D alignment |
| The winning duo | Inside components | The page structure |
The two combine: grid for the page skeleton, flexbox inside components. And centering, the favorite trick question: display: grid; place-items: center; on the parent — two lines.
Modern units and tools:
rem(relative to the root) for text: respects the user’s font-size setting — unlike frozenpx. That’s an accessibility issue, not a style one.clamp(min, preferred, max): fluid typography without a media query —font-size: clamp(1rem, 2.5vw, 1.5rem).dvh(dynamic viewport height): fixes the classic100vhbug on mobile, where the URL bar hides the bottom of the page.- Custom properties (
--accent: #0057b8): real live variables inside the cascade, overridable per context (dark theme, component) — something Sass variables, compiled then frozen, cannot do. - Container queries (in passing):
@containeradapts a component to its container’s size, not the screen’s. The missing link of per-component responsive design: a card reused in a narrow sidebar or a wide area adapts by itself.
Mobile-first: base styles target the small screen, then @media (min-width: …) queries enrich on the way up. Simpler to reason about — you add instead of undoing — and aligned with real-world traffic.
Key concepts to master
Accessibility, in order of importance:
- Semantic HTML first:
<button>,<a>,<nav>,<main>,<label>linked to its input. Most of accessibility is free when the right elements are used. - Text alternatives: descriptive
alton informative images;alt=""(empty, not missing) on decorative ones, so screen readers skip them instead of reading the file name. - Contrast: 4.5:1 minimum for normal text (WCAG AA), 3:1 for large text. Checkable in two clicks (DevTools, WebAIM).
- Visible focus:
:focus-visibleshows a clear outline during keyboard navigation without polluting mouse clicks. Removing the outline with no replacement makes the site unusable by keyboard. - Keyboard navigation: everything clickable must be reachable (Tab) and activatable (Enter/Space). Zero-cost test: drop the mouse for five minutes and traverse your page.
- ARIA as a last resort: for states HTML cannot express (
aria-expanded,aria-live). The first rule of ARIA, written in black and white by the W3C: don’t use ARIA when a native element is enough.
An accessible component, in full:
<!-- A real <button>: focus, role, keyboard — all native -->
<button class="menu-btn" aria-expanded="false" aria-controls="menu">
Menu
</button>
<ul id="menu" hidden>…</ul>
<style>
.menu-btn {
font-size: 1rem; /* rem: follows the user's setting */
padding: 0.5em 1em; /* em: follows the text size */
cursor: pointer;
}
.menu-btn:focus-visible { /* visible on keyboard, not on click */
outline: 3px solid var(--accent, #0057b8);
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { /* respects the system setting */
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
</style>
The only ARIA needed here: aria-expanded (the open/closed state, which HTML cannot express) and aria-controls (the link to the menu). The JS toggles aria-expanded and hidden — that’s all.
⚠️ The clickable div —
<div onClick={...}>is the original sin of modern front-end: no focus (invisible to Tab), no role (mute for screen readers), no keyboard activation (Enter/Space ignored), no:disabledstate. Making it accessible requirestabindex="0",role="button", akeydownhandler… that is, reimplementing, badly, what<button>gives you in one tag. If it’s clickable:<button>for an action,<a>for navigation.
💡 prefers-reduced-motion — some users (vestibular disorders, motion sensitivity) disable animations in their OS. That setting reaches CSS through
@media (prefers-reduced-motion: reduce): honoring it costs five lines, ignoring it makes the site physically unpleasant. Mentioning it in an interview signals an above-average a11y culture.
In an interview
“What is CSS specificity?” — The mechanism that settles two rules targeting the same element: a triplet (id, classes/pseudo-classes/attributes, elements) compared position by position, left to right. One id beats any number of classes; on an exact tie, the last declared rule wins; inline style tops everything, and !important short-circuits the mechanism. Good practice: keep it low and homogeneous (classes) to stay in control of overrides.
“Flexbox or Grid: how do you choose?” — One dimension → flexbox: navbar, row of buttons, items distributing along an axis. Two dimensions → grid: page layout, gallery, rows and columns defined together. They combine: grid for the structure, flexbox inside components. Bonus: place-items: center on a grid parent centers an element in two lines.
“Why a <button> rather than a clickable <div>?” — The native element gives you for free: keyboard focus, a role announced to screen readers, Enter/Space activation, the :disabled state, form behavior. The div requires reimplementing everything (tabindex, role, keydown) and the result is always incomplete. The rule: ARIA and JS don’t fix bad HTML.
“How do you make a site responsive?” — Mobile-first: base styles for small screens, min-width media queries to enrich. Fluid layouts with grid/flexbox (minmax(), auto-fit), fluid type with clamp(), images at max-width: 100%. And for components reused in contexts of different widths: container queries.
“What is ARIA, and when do you use it?” — Attributes describing roles and states to assistive technologies when native HTML isn’t enough: aria-expanded for a dropdown menu, aria-live for dynamically updated content. First rule of ARIA: prefer the native element. And bad ARIA is worse than no ARIA: it promises screen readers behaviors the JS doesn’t deliver.
Pitfalls & misconceptions
!importantto “fix” a conflict: it hides the conflict and triggers the arms race — the next one will require one more!important. The real fix: understand which rule wins and why, then lower the specificity.- “Accessibility is for the end of the project”: retrofitting a11y onto bad HTML costs ten times the price of starting with the right elements. And the audience is wide: permanent, temporary (broken arm) and situational (bright sunlight, baby in one arm) impairments.
outline: nonewith no replacement: the classic “it’s ugly” move that makes the site unusable by keyboard.:focus-visiblesolves the aesthetics cleanly: outline on keyboard, nothing on click.- ARIA everywhere:
role="button"on a<button>, redundantaria-labels… Over-ARIA degrades the screen reader experience. The W3C docs say it literally: no ARIA is better than bad ARIA. pxfor text sizes: ignores the setting of a user who enlarged their system font.remfor text, always.- Testing only with a mouse on your own screen: five minutes on the keyboard + one contrast check catch half of the accessibility problems before review.
Going further
- MDN — Specificity and Introducing the CSS Cascade
- CSS-Tricks — A Complete Guide to Flexbox and A Complete Guide to CSS Grid
- web.dev — Learn CSS and Learn Accessibility — Google’s two free courses
- The A11Y Project — a pragmatic accessibility checklist
- WebAIM — Contrast Checker — check a contrast ratio in two seconds
- W3C — Using ARIA: the first rule of ARIA