Chapitre 60 : Responsive design fluide avec minmax() et repeat()
Concepts clés : Fonctions CSS minmax, repeat, auto-fill, auto-fit
Dans le développement d'interfaces modernes, l'objectif est de s'éloigner des "breakpoints" rigides (Media Queries) pour tendre vers un design intrinsèque. Un design intrinsèque est un layout qui s'adapte à la taille de son contenu et à l'espace disponible sans nécessiter de règles spécifiques pour chaque taille d'écran.
L'alliance des fonctions minmax(), repeat() et des mots-clés auto-fill/auto-fit au sein de CSS Grid permet de créer des systèmes de grille totalement fluides et autonomes.
La fonction minmax()
1. Quoi
La fonction minmax(min, max) définit une taille de piste (colonne ou ligne) qui peut varier entre un seuil minimum et un seuil maximum.
- Le premier argument est la valeur minimale. Si le contenu est plus petit ou si l'espace manque, la piste ne descendra jamais en dessous de cette valeur.
- Le second argument est la valeur maximale. La piste ne dépassera jamais cette taille, même si l'espace disponible est immense.
2. Pourquoi
En production, utiliser des valeurs fixes (px) ou des pourcentages stricts (%) crée souvent des problèmes de débordement ou des espaces vides disgracieux. minmax() permet de garantir que :
- Un élément reste lisible (ne devient pas trop étroit).
- Un élément ne s'étire pas de manière disproportionnée sur des écrans Ultra-Wide.
3. Comment
A. Syntaxe de base
.container {
display: grid;
/* La colonne fera au minimum 200px et au maximum 1 fraction de l'espace restant */
grid-template-columns: minmax(200px, 1fr);
}
B. Cas concret : Grille de cartes adaptative
Imaginons un dashboard où les cartes doivent occuper tout l'espace mais ne jamais descendre sous les 300px pour préserver l'ergonomie.
.dashboard-grid {
display: grid;
gap: 1.5rem;
/* On définit 3 colonnes qui s'adaptent entre 300px et 1fr */
grid-template-columns: repeat(3, minmax(300px, 1fr));
}
C. Limitations
minmax()ne peut pas être utilisé à l'intérieur degrid-auto-columnsougrid-auto-rowssi on utilise des valeurs de pourcentage sans que le parent ait une taille définie.- L'utilisation de
minmax(0, 1fr)est une technique courante pour permettre à un élément de rétrécir en dessous de sa taille de contenu minimale (utile pour éviter que des longs mots ou des images ne cassent la grille).
4. Zone de Danger
❌ Erreur commune : Utiliser minmax(200px, 100%) dans une grille avec plusieurs colonnes.
Le 100% se réfère à la largeur du container. Si vous avez deux colonnes à 100%, vous créez un débordement horizontal immédiat.
✅ Bonne pratique : Utiliser 1fr comme valeur maximale pour distribuer l'espace proportionnellement.
La puissance de repeat() avec auto-fill et auto-fit
C'est ici que le responsive design devient "intelligent". Au lieu de spécifier un nombre fixe de colonnes (ex: repeat(3, ...)), on utilise des mots-clés de remplissage automatique.
1. Quoi
repeat(auto-fill, minmax(min, max)): Le navigateur crée autant de colonnes que possible pour remplir la ligne, même si elles restent vides.repeat(auto-fit, minmax(min, max)): Le navigateur crée autant de colonnes que possible, mais si des colonnes sont vides, il étire les colonnes occupées pour remplir tout l'espace.
2. Pourquoi
Cela élimine le besoin de Media Queries pour les grilles de produits ou de galeries. Le layout passe de 1 à 2, 3, 4 colonnes dynamiquement selon la largeur du viewport, sans aucune ligne de code @media.
3. Comment
Cas concret : Galerie de photos "Zero Media Query"
.gallery {
display: grid;
/*
On demande au navigateur de remplir la ligne avec autant de colonnes
de 250px minimum que possible. Le reste de l'espace est réparti équitablement (1fr).
*/
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
Différence visuelle cruciale
Si vous avez seulement 2 éléments dans un container de 1200px :
- Avec
auto-filletminmax(250px, 1fr): Vous aurez 2 colonnes de ~250px et un grand vide à droite (car le navigateur a "réservé" des places pour d'autres colonnes potentielles). - Avec
auto-fitetminmax(250px, 1fr): Les 2 éléments s'étireront pour faire chacun 600px (car les colonnes vides sont "collapsées").
4. Zone de Danger
❌ Erreur commune : Confondre auto-fill et auto-fit pour des interfaces de type "Dashboard" où l'alignement strict est requis.
✅ Bonne pratique :
- Utilisez
auto-fitpour des galeries d'images ou des listes de cartes où vous voulez que le contenu occupe toujours toute la largeur. - Utilisez
auto-fillquand vous voulez maintenir une taille de colonne cohérente, même si la ligne n'est pas complète (ex: un catalogue de produits où l'on veut éviter que 2 produits deviennent géants sur un écran large).
Logique de décision auto-fill vs auto-fit
Questions clés
1. Quelle est la différence fondamentale entre 1fr et auto-fit ?
Découvrir la réponse
1fr est une unité de mesure (une fraction de l'espace disponible). auto-fit est un mot-clé utilisé dans la fonction repeat() pour définir dynamiquement le nombre de pistes. On utilise généralement les deux ensemble : repeat(auto-fit, minmax(200px, 1fr)).
2. Pourquoi utiliser minmax(0, 1fr) au lieu de simplement 1fr ?
Découvrir la réponse
Par défaut, la valeur minimale d'une piste 1fr est auto. Si un élément à l'intérieur de la cellule (comme un long lien URL ou une image large) dépasse la largeur du container, la colonne s'élargira pour s'adapter au contenu, brisant ainsi la grille. minmax(0, 1fr) force la colonne à pouvoir rétrécir jusqu'à 0, permettant au contenu de déborder ou de s'enrouler (avec overflow: hidden ou word-break).
3. Quand privilégier auto-fill sur auto-fit ?
Découvrir la réponse
auto-fill est préférable lorsque vous voulez que vos éléments conservent une taille stable et prévisible, même s'il y a peu d'éléments. Par exemple, dans un système de grille de design strict où une carte ne doit jamais dépasser 400px même s'il n'y a qu'une seule carte sur la ligne.
4. Peut-on combiner minmax() avec des pourcentages ?
Découvrir la réponse
Oui, mais c'est risqué. minmax(20%, 50%) fonctionne, mais cela rend le layout dépendant de la taille du parent. Pour un responsive fluide, le couple [Valeur Fixe (px/rem), 1fr] est le standard industriel car il combine une contrainte physique minimale et une flexibilité proportionnelle.
Mise en pratique
Exercice 1 : Reproduction guidée
Créez une grille de "badges" de compétences. Chaque badge doit faire au minimum 120px et s'étirer pour remplir l'espace. La grille doit s'adapter automatiquement sans aucune media query.
Découvrir la solution commentée
.skills-container {
display: grid;
/*
auto-fit : on étire les badges pour remplir la ligne
minmax(120px, 1fr) : minimum 120px, maximum partage équitable
*/
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 10px;
}
.badge {
background: #eee;
padding: 8px;
text-align: center;
border-radius: 4px;
}
Exercice 2 : Adaptation (Le piège du contenu)
Vous avez une grille de cartes utilisant repeat(auto-fit, minmax(250px, 1fr)). L'une des cartes contient un tableau très large qui force la colonne à s'élargir à 600px, cassant ainsi l'alignement des autres colonnes. Corrigez ce problème.
Code de départ (comportement bugué) :
<div class="grid">
<div class="card">
<h3>Carte normale</h3>
<p>Contenu court et lisible.</p>
</div>
<div class="card">
<h3>Carte avec tableau</h3>
<!-- Ce tableau est large et va forcer la colonne à s'élargir -->
<table>
<tr>
<th>Identifiant produit</th>
<th>Référence fournisseur</th>
<th>Désignation complète</th>
<th>Stock disponible</th>
</tr>
<tr>
<td>PRD-00123456</td>
<td>FOURNISSEUR-REF-XYZ-2024</td>
<td>Ordinateur portable 15 pouces haute performance</td>
<td>42 unités</td>
</tr>
</table>
</div>
<div class="card">
<h3>Autre carte normale</h3>
<p>Contenu court et lisible.</p>
</div>
</div>
/* CSS qui plante : la colonne contenant le tableau s'élargit
bien au-delà de 250px, cassant l'alignement de la grille */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* ← Le bug */
gap: 20px;
}
.card {
/* overflow: hidden manquant → le tableau déborde des bords de la carte */
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
border: 1px solid #ccc;
white-space: nowrap;
}
Le contenu white-space: nowrap empêche le texte de revenir à la ligne, mais c'est la valeur minimale de minmax(250px, ...) qui est le vrai problème : 250px se réfère ici à la taille du contenu intrinsèque. Cherchez comment utiliser minmax(0, 1fr) ou min() pour contraindre la colonne à ne jamais dépasser sa taille théorique.
Découvrir la solution commentée
.grid {
display: grid;
/*
On remplace 250px par minmax(0, 250px) ou on utilise
minmax(0, 1fr) pour permettre à la colonne de
ne pas être poussée par le contenu "intrinsèque"
*/
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
/*
Note : Pour garder le minimum de 250px tout en évitant
le bug du contenu, on peut utiliser :
*/
/* grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr)); */
gap: 20px;
}
.card {
overflow: hidden; /* Empêche le contenu de pousser les murs */
}
Exercice 3 : Conception (Système de Pricing)
Concevez un système de pricing avec 3 offres.
- Sur grand écran : 3 colonnes égales.
- Sur écran moyen : 2 colonnes (la 3ème passe à la ligne).
- Sur petit écran : 1 colonne.
- Contrainte : Les cartes ne doivent jamais être plus petites que
300pxet ne doivent jamais être plus larges que450pxpour éviter l'effet "bandeau" sur desktop.
Découvrir la solution commentée
.pricing-grid {
display: grid;
/*
1. auto-fit pour l'adaptation automatique
2. minmax(300px, 450px) pour borner la taille
3. On centre la grille avec justify-content pour
éviter que les cartes soient collées à gauche
quand elles atteignent 450px
*/
grid-template-columns: repeat(auto-fit, minmax(300px, 450px));
justify-content: center;
gap: 2rem;
}
.pricing-card {
border: 1px solid #ccc;
padding: 2rem;
text-align: center;
}