Mis à jour 15 juillet 2026

Construire la grille en CSS pur

Une page construite sur un framework de l’ère 2013 annonçait sa mise en page dans chaque balise : class="col-xs-12 col-sm-6 col-md-4" sur carte après carte, une classe par élément et par point de rupture, avec une feuille de style de framework embarquée pour donner un sens à ces classes. L’équivalent moderne de tout cet appareillage tient dans une vingtaine de lignes de CSS que vous pouvez lire d’une traite.

Un système de grille CSS en CSS moderne est un ensemble de propriétés personnalisées portant les décisions propres à chaque point de rupture — nombre de colonnes, gouttière, marge — redéclarées à l’intérieur de media queries, plus trois classes qui les consomment : un conteneur qui plafonne et centre la page, une grille qui dispose les colonnes, et des classes de portée qui permettent aux éléments de réclamer des largeurs de colonnes. Aucune dépendance à un framework, aucune étape de build ; le moteur de mise en page du navigateur fait le travail que le framework simulait autrefois.

Cet article parcourt ce code ligne par ligne : la couche des variables, les trois classes, le piège de minmax(0, 1fr), et l’astuce de clampage en une ligne qui remplace la soupe de classes par point de rupture. C’est la moitié « implémentation » du sujet layout grid — ce que les colonnes, les gouttières et les points de rupture devraient être relève du reste du cluster.

Comment la grille se répartit-elle entre variables et classes ?

L’architecture comporte exactement deux couches, et cette séparation est tout l’intérêt.

Les variables sont les décisions de design. --grid-cols, --grid-gutter et --grid-margin contiennent les valeurs d’un palier à la fois : 4 / 16px / 16px sur téléphone, redéclarées en 8 / 24px / 29px à partir de 768px et 12 / 24px / 66px à partir de 1200px. --container contient le plafond global. Ces quelques chiffres par palier constituent toute la politique de mise en page — tout ce qu’une équipe décide réellement quand elle décide « la grille ».

Les classes sont la mécanique. .grid-container, .grid et les portées .col-N ne contiennent aucun chiffre en propre ; elles se contentent de lire les variables. La mécanique s’écrit une fois et se retouche rarement — une refonte ou un nouveau point de rupture ne change que les blocs :root.

Si vous travaillez avec des design tokens, le parallèle est exact : les variables sont des tokens de mise en page à l’exécution. Les mêmes valeurs de colonnes/gouttière/marge qui vivent dans la section layout d’un fichier de tokens deviennent ici des propriétés personnalisées, et les classes jouent le rôle que les composants jouent partout ailleurs dans un système de tokens — consommateurs des décisions, jamais propriétaires.

À quoi ressemble le CSS complet de la grille ?

Voici la forme de l’export CSS de Scale Composer pour sa grille par défaut, annoté :

/* Tokens de grille
 * Largeur max globale : 1200px
 * Mobile :   ≥0px    →  4 cols · gouttière 16px · marge 16px
 * Tablette : ≥768px  →  8 cols · gouttière 24px · marge 29px
 * Desktop :  ≥1200px → 12 cols · gouttière 24px · marge 66px
 */

:root {                       /* le palier mobile est la valeur par défaut */
  --container: 1200px;
  --grid-cols: 4;
  --grid-gutter: 16px;
  --grid-margin: 16px;
}

@media (min-width: 768px) {   /* la tablette redéclare les décisions */
  :root {
    --grid-cols: 8;
    --grid-gutter: 24px;
    --grid-margin: 29px;
  }
}

@media (min-width: 1200px) {  /* le desktop les redéclare à nouveau */
  :root {
    --grid-cols: 12;
    --grid-gutter: 24px;
    --grid-margin: 66px;
  }
}

.grid-container {             /* plafonne et centre la page */
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--grid-margin);
}

.grid {                       /* dispose les colonnes */
  display: grid;
  grid-template-columns: repeat(var(--grid-cols), minmax(0, 1fr));
  gap: var(--grid-gutter);
}

/* Portées — clampées au nombre de colonnes du palier courant */
.col-1  { grid-column: span min(1, var(--grid-cols)); }
.col-2  { grid-column: span min(2, var(--grid-cols)); }
/* … .col-3 à .col-11 suivent le même schéma … */
.col-12 { grid-column: span min(12, var(--grid-cols)); }

Les trois classes répartissent le travail proprement. .grid-container possède le cadre de la page : max-width la plafonne, margin-inline: auto la centre, padding-inline maintient le contenu à distance du bord du viewport, de la valeur de la marge du palier. .grid possède les colonnes : repeat(var(--grid-cols), minmax(0, 1fr)) crée des pistes fluides égales et gap place la gouttière entre elles — les mécaniques de base de CSS Grid se chargent de toute l’arithmétique. Les classes .col-N ne possèdent rien d’autre qu’une revendication : s’étendre sur N colonnes, quelle que soit la colonne du moment.

Ouvrez cet export, annoté, dans Scale Composer — la vue grille génère le bloc ci-dessus à partir de ses réglages par point de rupture, chaque gouttière et chaque marge étant alignées sur l’échelle d’espacement partagée.

La vue grille de Scale Composer aux côtés de son export CSS généré : trois paliers de points de rupture sous forme de propriétés personnalisées, plus les classes conteneur, grille et portée

Pourquoi minmax(0, 1fr) plutôt que 1fr seul ?

Parce que 1fr seul a un plancher. C’est un raccourci pour minmax(auto, 1fr), et auto signifie « au moins la taille minimale de ce contenu ». Placez une longue URL insécable, un tableau large ou un bloc <pre> dans une colonne d’une grille repeat(12, 1fr) et cette colonne dépasse discrètement sa juste part ; les onze autres se contractent pour lui faire de la place, et la promesse de colonnes égales se rompt dans la ligne qui contient le contenu le plus large. C’est l’une des surprises de débogage les plus fréquentes dans Grid précisément parce que rien ne génère d’erreur — la mise en page est simplement fausse, et seulement dans les lignes au contenu récalcitrant.

minmax(0, 1fr) supprime le plancher. Chaque piste vaut exactement une fraction de l’espace libre, toujours ; un contenu plus large que sa colonne déborde de la colonne — visiblement, de façon corrigible — au lieu de tordre toute la grille autour de lui. Des pistes honnêtes, un débordement honnête.

Comment les portées survivent-elles aux points de rupture plus petits ?

Cette ligne est là où l’ère de la soupe de classes prend réellement fin :

.col-8 { grid-column: span min(8, var(--grid-cols)); }

Un span 8 naïf se comporte mal sur téléphone : le palier mobile a quatre colonnes explicites, et Grid honore une portée surdimensionnée en créant des pistes implicites — la grille à quatre colonnes devient silencieusement une grille à huit colonnes, et tout le reste se contracte et se désaligne. Envelopper la portée dans min(N, var(--grid-cols)) réévalue plutôt la revendication à chaque palier : un élément .col-8 prend huit colonnes sur douze en desktop, les huit sur tablette, et se clampe aux quatre sur un téléphone — pleine largeur, ce qui correspond à l’empilement. Pas de deuxième classe, pas de media query supplémentaire.

L’ère des frameworks résolvait le même problème avec des classes par palier (col-md-8 col-sm-4) : une décision par élément et par point de rupture, encodée dans le balisage. Le clampage remplace cette taxonomie par une valeur par défaut — et là où le repli par défaut n’est pas le design souhaité, une portée redéclarée à l’intérieur d’une media query devient l’exception plutôt que le système.

À quoi ressemble une page construite dessus ?

Une page à trois sections — hero, article avec barre latérale, rangée de cartes — c’est du balisage plus des revendications :

<body class="grid-container">
  <header class="grid">
    <h1 class="col-12">Hero — full width at every tier</h1>
  </header>

  <main class="grid">
    <article class="col-8">Article body</article>
    <aside class="col-4">Sidebar</aside>
  </main>

  <section class="grid">
    <div class="col-4">Card</div>
    <div class="col-4">Card</div>
    <div class="col-4">Card</div>
  </section>
</body>

Au palier desktop, les chiffres tombent ainsi : le conteneur plafonne à 1200px, les marges prennent 2 × 66px, les onze gouttières prennent 11 × 24px = 264px, et chaque colonne obtient (1200 − 132 − 264) ÷ 12 = 67px. L’article s’étend sur 8 × 67 + 7 × 24 = 704px, la barre latérale et chaque carte 340px. Sur un téléphone de 375px, chacune de ces portées se clampe à quatre colonnes et la page devient une pile propre à une seule colonne — rien de plus n’a été écrit pour que cela se produise.

Que ne peut pas faire une grille de vingt lignes ?

Elle positionne des boîtes sur un unique jeu de colonnes partagé, et c’est tout ce qu’elle fait. Elle n’a aucune réponse pour aligner l’intérieur de cartes sœurs les unes sur les autres (c’est le travail de subgrid), pas d’agencement en maçonnerie (masonry), pas de zones nommées, aucune astuce de placement automatique. Rien de tout cela n’est un défaut du modèle ; cela marque le point où vous cessez d’utiliser le système et commencez à utiliser CSS Grid directement — grid-template-areas ou subgrid sur le composant précis qui en a besoin. Le système couvre la page ; Grid lui-même couvre les cas particuliers.

Exportez une grille avec vos propres chiffres

La façon la plus rapide de vous approprier ce modèle est de le générer à partir de décisions que vous avez prises vous-même. Réglez les colonnes, les gouttières et les marges par point de rupture dans la vue grille — chaque mesure parcourt la même échelle d’espacement où puise le reste du système — puis lisez la feuille de style qui en découle : exportez le CSS de la grille avec vos propres valeurs de points de rupture dans Scale Composer.

Continuer la lecture

  • Qu'est-ce qu'une grille à 12 colonnes ?

    Une grille à 12 colonnes divise la page en douze colonnes égales avec des gouttières fixes. Pourquoi douze l'emporte : les moitiés, les tiers, les quarts et les sixièmes tombent tous sur des colonnes entières.

  • Étendues de colonnes et imbrication

    Comment fonctionne l'étendue de colonnes sur une grille : la grammaire des étendues, les motifs de page comme 8+4 et 4+4+4, le choix des étendues selon le contenu et l'alignement, et l'imbrication propre des grilles.