- 1 Principes de base
- 2 Flexbox
- 3 Grille et sous-grille
- 4 Requêtes de conteneur
- 5 Superpositions natives, positionnement des ancres et contextes d'empilement
- 6 Suivi du dépassement et stabilité de la mise en page
- 7 Mécanismes de la fenêtre d'affichage et distribution des pistes
- 8 lignes de grille (ou "masonry")
1 Principes de base
Dans la mesure du possible, appuyez-vous sur le moteur de mise en page du navigateur pour améliorer les performances. Utilisez le dimensionnement intrinsèque, les propriétés logiques et aspect-ratio avant de recourir à des dimensions codées en dur ou à des requêtes média complexes.
1.1 Quel mode de mise en page utiliser ?
Parcourez l'arbre de décision de haut en bas et arrêtez-vous à la première correspondance. Notez que les mises en page peuvent être imbriquées les unes dans les autres et que chaque décision est basée sur le cas d'utilisation de ce conteneur.
- S'agit-il d'une simple ligne OU colonne d'éléments ? Utilisez flexbox : 1D, priorité au contenu, le contenu est distribué le long d'un seul axe.
- Un élément imbriqué doit-il s'aligner sur les pistes de la grille de son grand-parent ? Utilisez subgrid : 2D, axé sur les relations, hérite des pistes parentes pour que les petits-enfants puissent s'aligner sur les frères et sœurs.
- S'agit-il d'une structure de page ou de composant complexe avec des lignes ET des colonnes ? Utilisez grid : 2D, axé sur la mise en page, vous définissez le squelette et le contenu le remplit.
- Le contenu est-il un long texte qui doit être divisé en colonnes équilibrées ? Utilisez le mode multicolonne : flux 1D, style journal.
- Les éléments sont-ils de hauteurs différentes et doivent-ils être emballés de manière compacte ? Utilisez grid avec
grid-auto-flow: densedès aujourd'hui. N'utilisez la disposition en maçonnerie native (alias "grid lanes") que lorsqu'elle est disponible dans votre cible Baseline (voir §8). - Un élément doit-il flotter au-dessus de la page et rester lié spatialement à un déclencheur, même au-delà des limites du DOM ou des contextes d'empilement ? Utilisez le positionnement d'ancrage :
anchor-namesur le déclencheur,position-anchorsur la superposition (voir §5).
1.2 Principes de fonctionnement
- Utilisez des propriétés logiques (
inline-size,block-size,margin-inline,padding-block,inset-inline-start) pour les dimensions et l'espacement de la mise en page. Pour en savoir plus, consultez CSS : architecture moderne. - Appliquez le modèle mental "contenu d'abord" ou "mise en page d'abord" : flexbox lorsque les éléments dictent le flux, grille lorsque vous définissez d'abord le squelette.
- Utilisez les raccourcis
place-*(place-content,place-items,place-self) pour aligner les deux axes dans une seule déclaration. - Utilisez le dimensionnement intrinsèque (
min-content,max-content,fit-content()) et les pistes flexibles (fr,minmax()) avant les pistes fixeswidth/height: moins de requêtes média, des mises en page plus résilientes. - N'utilisez PAS
overflow: hiddenpour masquer les problèmes de mise en page. Corrigez-les à la source. Par exemple, certains éléments remplacés comme<canvas>,<img>,<svg>,<video>et<iframe>utilisentdisplay: inlinepar défaut, ce qui peut ajouter un espace dans certaines mises en page. Au lieu de masquer l'espace avecoverflow, supprimez-le en appliquant une valeur d'affichage externe de bloc (par exemple,display: block,grid,flex, etc.). - Utilisez
aspect-ratiopour réserver de l'espace pour les contenus multimédias et éviter les décalages de mise en page avant le chargement des éléments.
.sidebar { inline-size: max-content; } /* Size to longest unbreakable token. */
.main-content { inline-size: fit-content; } /* Grow to available space, no further. */
.media { aspect-ratio: 16 / 9; inline-size: 100%; block-size: auto; }
body.centered { display: grid; place-content: center; min-block-size: 100dvb; }
Pour en savoir plus sur
calc-size()et le dimensionnement intrinsèque tenant compte des contraintes, consultez Calculer avec des tailles intrinsèques.
2 Flexbox
Mise en page unidimensionnelle : les éléments s'écoulent le long d'un seul axe principal avec un alignement sur l'axe transversal. Utilisez-le pour les barres de navigation, les barres d'outils, les lignes d'éléments et toute distribution sur une seule ligne ou colonne.
À faire :
- Établissez un contexte avec
display: flexet définissez l'axe principal avecflex-direction(rowpar défaut). - Utilisez
flex-wrap: wrapchaque fois qu'un dépassement est possible.nowrapsansoverflow: auto/hiddendébordera sur les fenêtres d'affichage étroites. - Superposez
flex-wrap: balanceaprèsflex-wrap: wrapsur les lignes encapsulées d'éléments compacts (comme les nuages de mots clés, les pastilles de filtre, les groupes de boutons ou les liens de navigation) pour répartir les éléments de manière uniforme sur les lignes et éviter qu'un seul élément ne se retrouve isolé sur la dernière ligne. Les navigateurs non compatibles reviennent àwrap. - Utilisez la propriété abrégée
flex<grow> <shrink> <basis>(par exemple,flex: 1 1 250px) sur les éléments plutôt que de définirflex-grow/flex-shrink/flex-basisindividuellement. - Utilisez
gap(ou la version longuerow-gap/column-gap) pour l'espacement entre les éléments au lieu des marges enfants. - Ajoutez le préfixe
safeà l'alignement positionnel (par exemple,align-items: safe center) pour que le contenu sélectionnable ne soit pas tronqué lorsque le conteneur est plus étroit que son contenu. - Poussez un seul élément à l'extrémité de l'axe principal avec
margin-inline-start: auto(oumargin-block-start: auto). C'est la solution standard. - Remplacez l'alignement transversal par élément par
align-self. - Utilisez
align-itemspour centrer tous les éléments sur l'axe transversal,margin: autosur un seul élément pour le centrer sur les deux axes indépendamment, etalign-contentuniquement lorsque le conteneur s'ajuste et dispose d'un espace supplémentaire entre les lignes. - Définissez
min-inline-size: 0(oumin-width: 0) sur les éléments flex qui contiennent du contenu long et insécable (URL, code, chaînes longues). Par défaut, les éléments flex ne se réduisent pas en dessous de la taille de leur contenu, ce qui entraîne un dépassement.
À ne pas faire :
- N'utilisez pas
justify-selfsur les éléments flex. Cette propriété ne fonctionne que sur les mises en page de type grille, bloc et positionnement absolu. Utilisez plutôt des marges automatiques. - N'utilisez pas
orderniflex-direction: *-reversepour réorganiser le contenu interactif. Elles ne modifient que l'ordre visuel. L'ordre du DOM détermine toujours la sélection séquentielle. Par conséquent, le flux de tabulation au clavier ne correspondra pas à ce que l'utilisateur voit. - Ne confondez pas
space-around(demi-espace aux extrémités) avecspace-evenly(espaces égaux avant, entre et après). - N'oubliez pas l'inversion des axes : lorsque
flex-direction: column,justify-contents'aligne sur l'axe de bloc etalign-itemss'aligne sur l'axe intégré, soit l'inverse de la valeur par défaut. - Ne dimensionnez pas à la fois le conteneur et ses enfants pour qu'ils se remplissent mutuellement. C'est une source courante de dépassement et de résultats inattendus. Donnez une taille définie à un côté.
- Ne définissez pas à la fois
flex-basisetwidth/inline-sizesur le même élément.flex-basisest prioritaire dans un contexte Flex, etwidthest ignoré. Utilisezflex-basis(ou le raccourciflex) comme source unique de vérité pour dimensionner les éléments flex.
.card-grid { display: flex; flex-flow: row wrap; gap: 1rem; }
.card-item { flex: 1 1 250px; } /* grow, shrink, basis */
.card-item-action { margin-inline-start: auto; } /* Push to main-axis end. */
.toolbar { display: flex; align-items: safe center; }
.tag-list { display: flex; flex-wrap: wrap; flex-wrap: balance; gap: 0.5rem; }
3 Grille et sous-grille
Mise en page bidimensionnelle : définissez explicitement les lignes ET les colonnes, ou laissez le moteur les déduire. La sous-grille permet à une grille imbriquée d'hériter des pistes de son parent afin que les petits-enfants s'alignent sur les frères et sœurs.
Choisir les caractéristiques de la grille :
- Savez-vous exactement de combien de colonnes vous avez besoin ?
- Oui : utilisez des pistes explicites (
grid-template-columns: 200px 1fr,repeat(3, 1fr), etc.). - Les différentes colonnes ont-elles besoin de tailles différentes (barre latérale + contenu principal, en-tête couvrant l'ensemble) ? → Utilisez
grid-template-areaspour les régions nommées et lisibles. - Toutes les colonnes sont-elles uniformes ou positionnées uniquement par numéro de ligne ? → Utilisez
repeat(N, ...)ou des lignes nommées - Non (responsive, nombre d'éléments inconnu) : utilisez
repeat(auto-fit, minmax(min, 1fr)) - Les éléments de la dernière ligne doivent-ils s'étirer pour remplir l'espace restant ? →
auto-fit - Les pistes vides de la dernière ligne doivent-elles conserver leur taille minimale (en préservant les emplacements fantômes des colonnes) ? →
auto-fill
- Oui : utilisez des pistes explicites (
- Vous devez placer un élément à un endroit précis ?
- Oui : utilisez
grid-column: <start> / <end>ougrid-area: <name>. - Non (juste sur plusieurs pistes, la position du flux n'a pas d'importance) : utilisez
grid-column: span <n>
- Oui : utilisez
- Les éléments enfants doivent-ils hériter des tailles de pistes de la grille parente (alignement des bords irréguliers entre les éléments frères) ?
- Oui : utilisez la sous-grille sur l'axe concerné.
- Le nombre d'enfants par cellule est-il variable ? → sous-grille sur un seul axe ; utilisez
grid-auto-rows/grid-auto-columnspour l'autre - Le nombre d'enfants est-il fixe ? → La sous-grille sur les deux axes est correcte
- Non : grille standard, aucune sous-grille n'est nécessaire
À faire :
- Établissez un contexte avec
display: grid. - Utilisez
grid-template-areaspour les mises en page complexes au niveau de la page. Les noms des zones sont explicites, et la déclaration peut être alignée en lignes et en colonnes pour une lisibilité immédiate. - Utilisez
repeat(auto-fit, minmax(200px, 1fr))pour les grilles de fiches responsives qui étirent les pistes remplies pour remplir la ligne, ouauto-fillpour conserver les pistes répétées vides à leur taille minimale. - Utilisez
frpour une distribution proportionnelle des pistes etminmax(min, max)pour des pistes flexibles, mais limitées. - Positionnez les éléments avec
grid-column: span <n>pour les dimensionner sur plusieurs pistes,grid-column: <start> / <end>pour les placer sur des lignes spécifiques ougrid-area: <name>pour les régions nommées. - Utilisez une sous-grille (
grid-template-columns: subgridougrid-template-rows: subgrid) pour résoudre le problème de "bord irrégulier" dans les listes de fiches. Les éléments internes tels que les titres, les métadonnées et les incitations à l'action s'alignent sur les éléments frères. - Associez une déclaration de sous-grille à une déclaration
grid-template-rows/-columnsexplicite précédente en tant que solution de remplacement en cascade pour les anciens navigateurs.
À ne pas faire :
- Ne vous attendez pas à ce que la taille de la piste
auto-fit/auto-fillprovienne du contenu de l'élément. Elle provient de l'argument de taillerepeat(). - N'utilisez pas
grid-auto-flow: densesur du contenu interactif. Il regroupe efficacement les éléments, mais les réorganise visuellement, ce qui perturbe l'ordre de navigation au clavier dans le DOM. - N'appliquez pas de sous-grille aux deux axes lorsque le nombre d'enfants est variable. Les éléments supplémentaires sont placés dans la dernière piste. Utilisez plutôt
grid-auto-rows/grid-auto-columnspour l'axe implicite. - Ne confondez pas
justify-items/align-items(aligne le contenu de l'élément dans sa piste) avecjustify-content/align-content(aligne les pistes de la grille dans le conteneur). Si vous utilisez la mauvaise, elle n'aura aucun effet. - N'utilisez pas
repeat(auto-fit/auto-fill, ...)sans uninline-sizedéfini sur le conteneur. Dansdisplay: inline-gridou un élément flex sans taille, le conteneur n'a pas de largeur à diviser, ce qui rend le nombre de pistes imprévisible.
3.1 Exemple de code : grille et sous-grille
Shell de la page : <main class="page-layout"> contient <header>, <aside>, un <section class="card-grid"> avec <div class="card"> enfants et <footer>.
/* Align grid-template-areas in rows and columns for readability. */
.page-layout {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
gap: 1.5rem;
}
header { grid-area: header; }
aside { grid-area: sidebar; }
footer { grid-area: footer; }
.card-grid {
grid-area: main;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-template-rows: auto 1fr; /* title block, body block */
gap: 1rem;
}
.card {
grid-row: span 2;
display: grid;
/* Same-cascade fallback: ignored when subgrid is supported. */
grid-template-rows: auto 1fr;
grid-template-rows: subgrid;
}
4 Requêtes de conteneur
Interrogez la taille (ou le style calculé) d'un conteneur ancêtre plutôt que de la fenêtre d'affichage. Modèle mental : requêtes de conteneur = contexte du composant ; requêtes média = mise en page globale et préférences de l'utilisateur (prefers-color-scheme, prefers-reduced-motion).
À faire :
- Établissez un contexte de confinement avec
container-type: inline-size(requêtes de largeur uniquement) oucontainer-type: size(les deux axes) sur un wrapper avant que ses descendants puissent être interrogés. - Nommez les conteneurs avec
container-name(ou l'abréviationcontainer:container: card / inline-size) lorsque des contextes imbriqués peuvent entrer en conflit. - Incluez les unités de requête de conteneur dans le calcul du type et de l'espacement fluides :
cqi/cqb(inline/bloc logique),cqw/cqh(physique),cqmin/cqmax. - Attribuez une
block-sizedéfinie au conteneur chaque fois quecontainer-type: sizeest utilisé. Sans cela, les descendants se réduisent, car le confinement de la taille force le conteneur à ignorer son contenu.
À ne pas faire :
- N'utilisez pas
block-sizecomme valeurcontainer-type, car elle n'est pas valide. Utilisezsizepour les deux axes. - Ne vous attendez pas à ce que la taille intrinsèque des enfants influence le conteneur après avoir déclaré
container-type. Le conteneur est calculé comme s'il n'avait pas d'enfants une fois que le confinement est actif. - Ne vous fiez pas aux unités de requête de conteneur dans les descendants d'un ancêtre non éligible. Elles reviennent à la petite fenêtre d'affichage (
svw/svh).
4.1 Exemple de code : typographie fluide utilisant des unités de requête de conteneur
.card-wrapper {
container: card / inline-size; /* shorthand for container-name / container-type */
}
@container card (inline-size > 400px) {
.content {
display: flex;
gap: 2rem;
}
}
.title {
/* Fluid type bound to the container width, not the viewport. */
font-size: clamp(1rem, 4cqi, 2rem);
}
Pour en savoir plus sur les modèles de style responsif basés sur les composants, consultez Style basé sur la taille et Scaling fluide.
5 Superpositions natives, positionnement des ancres et contextes d'empilement
Quand utiliser chaque primitive de superposition :
- Utilisez
popoverpour l'UI temporaire non modale (menus contextuels, toasts, info-bulles) : elle se trouve dans la couche supérieure, aucune gestion dez-indexn'est nécessaire. - Utilisez
<dialog>avec.showModal()pour les interactions modales qui nécessitent un piégeage du focus et un arrière-plan inerte. - Ne combinez pas
popoveret.showModal()sur le même élément, car il s'agit d'états d'exécution mutuellement exclusifs.
Positionnement des ancres (disposition spatiale des superpositions) :
- Utilisez
position-area(ouanchor()sur les encarts) etanchor-size()pour positionner et dimensionner une superposition par rapport à son déclencheur. - Utilisez
position-try-fallbacks: flip-block(ouflip-inline) pour permettre au navigateur de repositionner l'overlay lorsqu'il dépasse la fenêtre d'affichage. - Ne mélangez pas les mots clés physiques et logiques dans une même valeur
position-area. Choisissez un système de coordonnées. - Détectez la fonctionnalité avec
@supports (anchor-name: --x)et fournissez une solution de remplacement en position absolue.
Pour en savoir plus sur l'implémentation, les stratégies de polyfill et la référence de valeur
popover, consultez Contrôle déclaratif des boîtes de dialogue et des popovers et Info-bulles sensibles à la position. Pour en savoir plus sur le positionnement des ancres appliqué aux menus déroulants, aux menus contextuels et aux indicateurs d'onglets, consultez Menus déroulants adaptés à la fenêtre d'affichage et Soulignement des onglets de positionnement des ancres.
6 Suivi du dépassement et stabilité de la mise en page
Gérez les décalages de mise en page, les barres de défilement et le rognage de manière prévisible.
À faire :
- Utilisez
overflow: autopour que les barres de défilement n'apparaissent que lorsque le contenu dépasse réellement. - Utilisez
overflow: clippour couper le contenu sans établir de conteneur de défilement. Optez pour le débordement avecoverflow-clip-margin. - Utilisez
scrollbar-gutter: stablepour réserver de l'espace pour les barres de défilement et éviter les décalages de mise en page lorsque le contenu s'agrandit. - Utilisez
overscroll-behavior: contain(ounone) sur les zones de défilement imbriquées (comme les barres latérales, les fenêtres modales et les listes) pour empêcher les chaînes de défilement de se propager dans la page, ouoverscroll-behavior: chainsur les wrappers de défilement intermédiaires (comme les pistes de balayage pour afficher) lorsque le défilement excessif doit se propager à un défilement parent sans déclencher de rebond élastique local. Utilisez la triade
-webkit-line-clamp+display: -webkit-box+-webkit-box-orient: verticalpour la troncature multiligne. Malgré le préfixe, ce modèle est entièrement spécifié et n'est pas obsolète. Déclarez la propriété abrégéeline-clampsans préfixe à côté. Les navigateurs qui ne la prennent pas encore en charge l'ignoreront sans problème. À ne pas faire :N'utilisez pas
overflow: scrolllorsqueautosuffit.scrollforce l'affichage des barres de défilement même lorsqu'il n'y a rien à faire défiler.N'utilisez pas
overflow: hiddenlorsque vous souhaitez uniquement rogner :hiddenétablit un conteneur de défilement qui peut être défilé de manière programmatique.
.scrollable-list {
max-block-size: 400px;
overflow-y: auto;
scrollbar-gutter: stable; /* Reserve scrollbar space. */
overscroll-behavior: contain; /* No scroll chaining into the page. */
}
.snippet {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
line-clamp: 3; /* Ignored where unsupported. */
overflow: clip;
}
Pour en savoir plus sur
overflow: clipetoverflow-clip-margin, consultez Contrôle du rognage du dépassement. Pour en savoir plus sur le transfert de défilement imbriqué avecoverscroll-behavior: chaindans une UI de balayage pour afficher, consultez Balayer pour afficher. Pour en savoir plus sur la couleur, la taille et le thème de la barre de défilement, consultez Personnaliser la couleur ou l'épaisseur d'une barre de défilement, Mode sombre et Adapter la barre de défilement aux préférences de contraste élevé.
7 Mécanismes de la fenêtre d'affichage et distribution des pistes
- Utilisez
dvh/dvwpour les conteneurs de mise en page mobile qui doivent tenir compte des changements d'interface utilisateur du navigateur (réduction/développement de la barre d'URL). - N'utilisez pas
100vwpour une mise en page pleine largeur, car il ignore la largeur de la barre de défilement et entraîne un dépassement horizontal. Utilisez plutôt100%,100dvwou100svw.
Pour en savoir plus sur le point d'entrée du responsive design (unités de fenêtre d'affichage dynamiques, réservation d'espace pour les contenus multimédias, typographie fluide), consultez Responsive design.
8 voies de grille (ou maçonnerie)
La spécification est en cours de développement sous le nom "grid lanes" (par exemple, display: grid-lanes), tandis que les prototypes expérimentaux précédents utilisaient grid-template-rows: masonry.
À faire :
- Utilisez une grille avec
grid-auto-flow: densepour un empaquetage serré dès aujourd'hui, en acceptant que l'ordre du DOM ne corresponde pas à l'ordre visuel. - Utilisez plusieurs colonnes (
columns: 3; column-gap: 1rem) pour les flux de type "masonry" contenant beaucoup de contenu lorsque les éléments sont des fragments de document plutôt que des fiches de même importance. - Considérez
grid-template-rows: masonrycomme une amélioration progressive uniquement. Détectez les fonctionnalités avec@supports.
À ne pas faire :
- N'exigez pas
grid-template-rows: masonrytant que votre cible Baseline n'est pas à jour.
.gallery { columns: 3 200px; column-gap: 1rem; }
.gallery > * { break-inside: avoid; margin-block-end: 1rem; }
@supports (grid-template-rows: masonry) {
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry;
gap: 1rem;
columns: unset;
}
}