Queries de conteneur contre queries médias : décisions pour la page et décisions pour les composants
Apprenez quand il convient d’utiliser une requête médiatique et quand une requête de conteneur est plus adaptée, grâce à des exemples de cartes, de tableaux de bord et d’unités qui permettent aux composants réutilisables de s’adapter.
Sources: Container Queries vs Media Queries: How Modern CSS Changes Responsive Design
La plupart des approches CSS réactives dépendent encore d’une seule variable : la largeur de la fenêtre du navigateur. Cela fonctionne bien pour la page dans son ensemble, mais cela ne convient pas aux composants réutilisables, car une carte affichée dans une barre latérale et la même carte affichée dans une colonne principale large voient exactement le même champ de vision tout en disposant d’espaces très différents. Ce guide montre comment les requêtes de conteneur comblent cette lacune, où les requêtes médias restent l’outil le plus adapté, et comment combiner les deux avec des unités fluides pour créer un système réactif facile à gérer.
Une règle classique basée sur le champ de vision se présente ainsi : une fois que la fenêtre descend en dessous d’un point de rupture, la carte empile son contenu verticalement.
@media (max-width: 768px) {
.card {
flex-direction: column;
}
}
Rien dans ce système n’est défectueux. La faiblesse est conceptuelle : la règle apprend quelle est la largeur de la fenêtre, mais jamais celle de la carte. Dans une petite démonstration, ces valeurs restent synchronisées ; dans une application remplie de grilles, de barres latérales et de panneaux, elles s’éloignent l’une de l’autre, et c’est cette différence qui provoque des erreurs de mise en page. Les requêtes de conteneur permettent à un composant de se demander "combien d’espace ai-je réellement ?" au lieu de "quelle est la largeur de l’écran ?"
Pourquoi un point de rupture de vue afficheur induit en erreur une carte réutilisable
Prenons une carte de produit simple : une image à côté d’un bloc de texte contenant un titre, une courte description et un appel à l’action. Le code HTML est divisé en deux extraits ici, mais il s’agit d’un seul élément.
<article class="product-card">
<img src="product.jpg" alt="Product">
<div class="product-info">
<h2>Wireless Headphones</h2>
<p>Noise cancellation with 30-hour battery life.</p>
<button>Buy now</button>
</div>
</article>
La première étape de stylisation place généralement l’image et le texte côte à côte grâce à Flexbox, puis on ajoute un point de rupture de vue afficheur pour les superposer sur les petits écrans.
.product-card {
display: flex;
gap: 1rem;
}
@media (max-width: 768px) {
.product-card {
flex-direction: column;
}
}
Cela semble fonctionner correctement tant que la carte n’est pas réutilisée. Sur une page de bureau large, il y a suffisamment d’espace horizontal, et le layout côte à côte semble approprié.
Desktop page
┌───────────────────────────────────────────┐
│ │
│ Product Card │
│ ┌──────────┐ ┌─────────────────────┐ │
│ │ Image │ │ Product information │ │
│ └──────────┘ └─────────────────────┘ │
│ │
└───────────────────────────────────────────┘
Si l’on place exactement la même carte dans une barre latérale étroite, elle nécessite un layout empilé même si la fenêtre reste de taille bureau.
┌───────────────┐
│ │
│ Sidebar │
│ │
│ ┌───────────┐ │
│ │ Image │ │
│ ├───────────┤ │
│ │ Info │ │
│ └───────────┘ │
│ │
└───────────────┘
En plaçant plusieurs cartes dans une même ligne de tableau de bord, chacune d’elles occupe une largeur différente en fonction de sa colonne.
┌───────────────────────────────────────────┐
│ ┌─────────────┐ ┌──────────────────────┐ │
│ │ Card │ │ Card │ │
│ └─────────────┘ └──────────────────────┘ │
└───────────────────────────────────────────┘
Trois emplacements, trois largeurs différentes, une vue d’écran inchangée. Une règle basée sur la fenêtre ne peut pas les distinguer, ce qui fait que la carte de la barre latérale reste étroite.
À quoi servent réellement les requêtes médias
Une requête média évalue les propriétés de l’environnement dans lequel la page est affichée : dimensions de la zone de visualisation, orientation, palette de couleurs, type de pointeur, préférences de réduction du mouvement, etc. La requête de largeur en est un exemple courant.
@media (max-width: 768px) {
...
}
Le flux d’information est simple : le navigateur mesure la zone de visualisation, la requête correspond ou non, et le layout réagit en conséquence.
Viewport
↓
Media Query
↓
Layout changes
Cela fait des requêtes média l’outil idéal pour prendre des décisions qui relèvent véritablement de la page dans son ensemble. Un exemple typique est une interface à deux colonnes avec une barre latérale de largeur fixe :
.page-layout {
display: grid;
grid-template-columns: 1fr 300px;
}
En dessous d’une certaine largeur de fenêtre, l’interface se réduit à une seule colonne :
@media (max-width: 900px) {
.page-layout {
grid-template-columns: 1fr;
}
}
C’est là un usage approprié d’une requête média : le fait que la page dispose ou non d’espace pour une barre latérale relève bien de la question de la zone de visualisation. Les problèmes commencent lorsque le même mécanisme décide de l’agencement des éléments internes d’un composant individuel.
Comment fonctionnent les requêtes de conteneur
Une requête de conteneur permet à un élément de réagir à la taille d’un ancêtre que vous avez explicitement marqué comme conteneur de requête. Sa mise en place nécessite deux étapes. Tout d’abord, déclarez le conteneur :
.card-container {
container-type: inline-size;
}
La valeur inline-size indique au navigateur que les descendants peuvent interroger la dimension en ligne du conteneur, c’est-à-dire sa largeur dans les modes d’écriture horizontaux. Ensuite, écrivez une règle pour ce conteneur :
@container (max-width: 500px) {
.product-card {
flex-direction: column;
}
}
Les informations proviennent désormais du conteneur plutôt que de la fenêtre :
Container
↓
Container Query
↓
Component layout
La carte ne se soucie plus du fait que l’utilisateur utilise un téléphone ou un grand moniteur ; elle réagit à l’espace que son parent lui alloue.
Un détail qui embrouille les gens
Une requête de conteneur applique des styles aux descendants du conteneur, jamais au conteneur lui-même. C’est pourquoi les exemples associent toujours un élément d’encapsulation (.card-container, .card-wrapper) à un élément interne (.product-card). Si vous appliquez container-type sur .product-card puis effectuez une requête pour modifier son propre flex-direction, rien ne se passe. Gardez l’élément d’encapsulation et le composant en tant qu’éléments distincts.
Un deuxième détail : le mode de conteneur inline-size signifie que la largeur du conteneur ne peut plus être déduite de son contenu. Un conteneur qui est un enfant de niveau bloc dans un layout à flux normal ne pose pas de problème, car sa largeur provient de son parent. Un conteneur qui dépend d’une taille adaptative, comme un élément inline-block ou un élément positionné absolument sans largeur explicite, peut voir sa largeur réduite à zéro une fois le mode de conteneur appliqué.
Largeur de la vue d’écran versus largeur du composant
Le contraste devient évident dans un tableau de bord avec une colonne principale large et une colonne latérale plus étroite :
.dashboard {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 1rem;
}
Supposons une fenêtre de 1440 px. Une règle basée sur la vue d’écran pour la carte ressemblerait à ceci :
@media (max-width: 768px) {
.card {
flex-direction: column;
}
}
Sur cette fenêtre, la règle ne s’applique jamais. Pourtant, une carte située dans la colonne plus étroite peut ne faire que environ 350 px de large. La requête média ne prend en compte qu’un seul chiffre :
Viewport = 1440px
La carte se trouve avec une autre :
Component width = 350px
Seul le deuxième nombre décrit les véritables conditions de la carte, et seule une requête de conteneur peut y répondre.
Une configuration minimale de requête de conteneur
L’implémentation est courte. Marquez l’élément conteneur comme tel :
.card-wrapper {
container-type: inline-size;
}
Donnez à la carte un grille à deux colonnes lorsque son conteneur fait au moins 600 px de large :
@container (min-width: 600px) {
.product-card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
Recourez à un layout en bloc simple en dessous de cette largeur :
@container (max-width: 599px) {
.product-card {
display: block;
}
}
Le markup n’a besoin que de l’élément conteneur entourant la carte :
<div class="card-wrapper">
<article class="product-card">
...
</article>
</div>
La mise en page de la carte provient désormais de son conteneur, de sorte que déplacer le wrapper dans une autre colonne produit automatiquement la bonne mise en page. Notez que les deux règles utilisent min-width: 600px et max-width: 599px ; avec des largeurs fractionnaires, un conteneur peut se situer entre ces valeurs. La nouvelle syntaxe de plage, @container (width >= 600px) et @container (width < 600px), évite cet écart et mérite d’être privilégiée dans les nouveaux codes.
Pourquoi cela convient à une architecture basée sur des composants
Les requêtes de conteneur sont plus importantes qu’une nouvelle fonctionnalité CSS typique, car les interfaces utilisateur modernes sont composées de parties réutilisables, qu’il s’agisse de composants de framework comme React, Vue ou Angular, de Web Components sans framework, ou des éléments de base d’un système de conception partagé. Aucun de ces éléments ne devrait avoir à savoir dans quelle région de la page il se trouve. Prenons l’élément user-card : il peut s’afficher dans la zone de contenu principale :
<main>
<user-card></user-card>
</main>
Il peut également s’afficher dans une section latérale :
<aside>
<user-card></user-card>
</aside>
Ou encore il peut être répété à l’intérieur d’une grille de tableau de bord :
<div class="dashboard-grid">
<user-card></user-card>
<user-card></user-card>
<user-card></user-card>
</div>
Le codage en dur d’un point de rupture de vue dans ce composant implique une hypothèse qu’il n’a aucun moyen de vérifier :
@media (max-width: 768px) {
...
}
Le chiffre 768 ne dit rien sur le contexte réel du composant. Une requête de conteneur offre un meilleur cadre : avec autant d’espace disponible, utiliser ce type de mise en page. Si vos composants sont des blocs de construction indépendants du framework, la discussion sur l’endroit où se situe la frontière du framework dans une pile d’interfaces utilisateur réutilisables est un complément utile à cette idée.
Permettre à une carte de profil de s’adapter à son environnement
Voici une carte de profil compacte qui place un avatar à côté du nom et du rôle :
.profile-card {
display: flex;
gap: 1rem;
align-items: center;
}
Son conteneur d’encapsulation devient alors un conteneur de requête :
.profile-container {
container-type: inline-size;
}
Lorsque ce conteneur mesure 400 px de large ou moins, la carte empile ses éléments et centre leur contenu :
@container (max-width: 400px) {
.profile-card {
flex-direction: column;
text-align: center;
}
}
Dans un conteneur spacieux, l’avatar se trouve à côté du texte :
┌──────────────────────────────────────┐
│ [Avatar] John Smith │
│ Senior Developer │
└──────────────────────────────────────┘
Dans des situations difficiles, le même composant se réorganise verticalement :
┌──────────────────┐
│ │
│ [Avatar] │
│ │
│ John Smith │
│ Senior Developer │
│ │
└──────────────────┘
Aucun observateur de redimensionnement, aucune variante « compacte » supplémentaire, aucune classe activée par la page parente.
Les requêtes médias ont encore leur rôle
Les requêtes de conteneur ne remplacent pas les requêtes médias ; elles répondent à une question différente. Voici un moyen rapide de classer les décisions courantes :
- Fermer la navigation principale : requête média.
- Supprimer la barre latérale au niveau de la page : requête média.
- Changer un tableau entre un agencement horizontal et vertical : requête de conteneur.
- Adapter un composant réutilisable à son emplacement : requête de conteneur.
- Ajuster la typographie dans tout le site : requête média.
- Permettre à un widget de tableau de bord de réagir à la largeur de sa colonne : requête de conteneur.
- Changer l’ensemble du shell de l’application pour un agencement différent : requête média.
Un modèle mental : décisions globales et décisions de composants
Le moyen le plus clair de diviser les tâches est de séparer ce que la page décide de ce que chaque composant décide.
Les requêtes médias portent sur la zone de visualisation
La question derrière une requête média est :
"What is the viewport doing?"
Elles conviennent à :
- La structure de la page
- La navigation
- L’espacement global
- La typographie globale
- Les changements majeurs de mise en page
Les requêtes de conteneur portent sur l’environnement du composant
La question derrière une requête de conteneur est :
"What is my component's environment doing?"
Elles conviennent à :
- Les cartes
- Les widgets
- Les panneaux
- Les composants UI réutilisables
- Les modules de tableau de bord
- Les composants du système de design
Ajustement des tailles avec les unités de requête de conteneur
Les requêtes de conteneur ne sont pas seulement des blocs conditionnels. Le CSS définit également des unités de longueur relatives au conteneur de requête le plus proche, permettant ainsi aux valeurs de s’adapter continuellement au lieu de sauter à un point de rupture :
.title {
font-size: 5cqi;
}
Ici, cqi représente un pour cent de la taille en ligne du conteneur, donc 5cqi correspond à cinq pour cent de sa largeur. L’ensemble complet des unités :
cqw → container width
cqh → container height
cqi → container inline size
cqb → container block size
cqmin → smaller container dimension
cqmax → larger container dimension
Un schéma courant consiste à envelopper une unité de conteneur dans clamp() afin que la valeur s’adapte au conteneur sans jamais sortir d’une plage raisonnable :
.card-title {
font-size: clamp(1rem, 4cqi, 2rem);
}
Le titre s’adapte désormais à l’espace de la composante plutôt qu’à celui de la fenêtre, ce que des unités de vue d’écran comme vw ne peuvent pas exprimer. Deux précautions à prendre : si un élément n’a pas de conteneur parent de type query, ces unités recourent à de petites unités de vue d’écran, ce qui produira bien une valeur, mais pas celle que vous aviez prévue. De plus, maintenir des plafonds et des fonds pour rem à l’intérieur de clamp(), comme indiqué ci-dessus, est important pour l’accessibilité : une taille de police déterminée uniquement par la largeur du conteneur ne prend pas en compte les réglages de taille de texte de l’utilisateur.
Dénomination des conteneurs dans les applications plus complexes
Pour une petite page, un conteneur anonyme suffit :
.container {
container-type: inline-size;
}
Lorsque des conteneurs sont imbriqués, une règle simple @container correspond au conteneur ancêtre le plus proche, qui n’est pas nécessairement celui que vous visiez. L’abréviation container vous permet de donner un nom à un conteneur en même temps que son type :
.dashboard {
container: dashboard / inline-size;
}
Les règles peuvent alors cibler ce conteneur de manière explicite :
@container dashboard (min-width: 700px) {
.widget {
grid-template-columns: 1fr 1fr;
}
}
Comparez une condition sans nom :
@container (min-width: 700px)
avec une condition nommée :
@container dashboard (min-width: 700px)
La version nommée indique clairement son intention et continue de fonctionner même si quelqu’un ajoute un autre conteneur entre le tableau de bord et le widget par la suite.
Choisissez délibérément les limites des conteneurs
Les requêtes de conteneur sont puissantes, mais ce n’est pas une raison d’ajouter cette déclaration à chaque élément :
container-type: inline-size;
Chaque conteneur applique un mise en page, des styles et une définition de taille en ligne, ce qui modifie la manière dont cet élément peut être dimensionné ; par conséquent, les conteneurs devraient délimiter des frontières de composants significatives plutôt que d’être dispersés partout. Prenons par exemple un tableau de bord contenant des widgets :
<section class="dashboard">
<article class="widget">
<div class="widget-content">
...
</div>
</article>
</section>
Un choix judicieux consiste à faire du tableau de bord le conteneur nommé :
.dashboard {
container: dashboard / inline-size;
}
et à permettre à chaque widget de réagir en fonction de lui. La règle n’est pas « utiliser des requêtes de conteneur partout », mais plutôt « les utiliser là où le comportement dépend de l’espace disponible ».
Remplacer les points de rupture par des points de rupture basés sur le contenu
De nombreux feuilles de style contiennent une série de points de rupture pour la vue d’ensemble comme ceci :
@media (max-width: 1200px) {
...
}
@media (max-width: 1024px) {
...
}@media (max-width: 900px) {
...
}@media (max-width: 768px) {
...
}@media (max-width: 640px) {
...
}@media (max-width: 480px) {
...
}
Parfois, cette disposition est justifiée. Souvent, elle indique que les composants ont été conçus en fonction de la largeur de l’appareil plutôt que de leur contenu propre. Les requêtes de conteneur vous orientent vers une question différente : au lieu de demander « quel point de rupture l’équipe utilise-t-elle habituellement ? », demandez plutôt « à quelle largeur ce composant cesse d’être bien présenté ? » La réponse vous fournit un point de rupture basé sur le contenu :
@container (max-width: 420px) {
.card {
flex-direction: column;
}
}
Rien dans la valeur 420px ne correspond à un téléphone en particulier ; c’est simplement là que cette carte n’a plus d’espace. Les points de rupture choisis de cette manière restent valides face aux modifications de mise en page et aux nouveaux appareils.
Concevoir des composants indépendants de leur emplacement
Les requêtes de conteneur incitent également les équipes à créer des composants véritablement indépendants, dont le comportement est prévisible quel que soit l’endroit où ils sont affichés. Pensez à un groupe de boutons dans un système de conception : il peut se trouver à l’intérieur d’un formulaire sur une page :
Page
└── Form
└── Button Group
Dans une carte sur un tableau de bord :
Dashboard
└── Card
└── Button Group
ou dans une carte dans un panneau latéral :
Sidebar
└── Card
└── Button Group
La vue d’affichage est identique dans les trois cas ; l’espace, lui, ne l’est pas. Avec une requête de conteneur, le groupe s’adapte sans avoir connaissance de la structure qui se trouve au-dessus.
Un modèle de carte responsive réutilisable
Voici un modèle complet que vous pouvez adopter directement. Le marquage enveloppe la carte dans un élément conteneur ; à nouveau, le HTML est présenté en deux parties consécutives.
<div class="card-container">
<article class="card">
<img src="image.jpg" alt="">
<div class="card-content">
<h2>Performance Dashboard</h2>
<p>
Monitor application performance and infrastructure metrics.
</p>
<a href="#">View dashboard</a>
</div>
</article>
</div>
Le conteneur est déclaré comme tel :
.card-container {
container-type: inline-size;
}
La carte commence par un grille à une seule colonne affichant une image en format 16:9. Lorsque son conteneur atteint 600 px, elle passe à une colonne d’image fixe à côté du contenu et rend l’image carrée. Les règles sont écrites sans sauts de ligne entre elles, ce qui est valide en CSS mais mérite d’être reformatté lorsqu’on les colle dans une base de code.
.card {
display: grid;
gap: 1rem;
}.card img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}@container (min-width: 600px) {
.card {
grid-template-columns: 200px 1fr;
align-items: center;
} .card img {
aspect-ratio: 1;
}
}
Remarquez ce que cette feuille de style ne contient pas :
@media (max-width: 768px)
La carte ne prend jamais en compte la vue d’affichage. Toutes ses décisions se basent sur son conteneur.
Combinaison des requêtes de conteneur avec une grille auto-ajustable
Les requêtes de conteneur s’accordent particulièrement bien avec une grille qui détermine elle-même le nombre de colonnes :
.dashboard {
display: grid;
grid-template-columns:
repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
}
Avec repeat(auto-fit, minmax(280px, 1fr)), le navigateur adapte autant de colonnes d’au moins 280px que la ligne le permet et les étire pour remplir l’espace restant. Chaque widget dispose alors de son propre conteneur :
.widget-container {
container-type: inline-size;
}
et passe à un layout interne à deux colonnes lorsque son espace est suffisamment large :
@container (min-width: 500px) {
.widget {
grid-template-columns: 1fr 1fr;
}
}
Le tableau de bord s’adapte à une large gamme de résolutions sans points de rupture de vue : la grille détermine l’espace alloué à chaque widget, et chaque widget décide comment l’utiliser.
Le layout responsive est également une question d’ergonomie
Être affiché à l’écran ne signifie pas pour autant être facile à utiliser. Une rangée de boutons qui tient techniquement sur une carte étroite peut rester trop compacte et rendre les clics plus difficiles. Une requête de conteneur peut empiler ces actions et les étirer sur toute la largeur lorsque la carte est étroite (la règle est répartie en deux extraits) :
@container (max-width: 350px) {
.actions {
flex-direction: column;
}
.actions button {
width: 100%;
}
}
Les boutons empilés en largeur totale offrent des cibles de touch plus grandes et réduisent les clics accidentels. La mise en page peut suivre la même logique, s’adaptant aux limites lorsque la largeur du composant change :
.card-title {
font-size: clamp(1rem, 4cqi, 1.75rem);
}
Les valeurs spécifiques importent moins que le principe qui les sous-tend : le comportement réactif doit refléter les conditions dans lesquelles un composant est réellement utilisé, et non une estimation basée sur la taille de la fenêtre.
Où les requêtes médias restent le choix approprié
Les requêtes de conteneur ne sont pas automatiquement la meilleure option. La navigation globale constitue un cas clair où les requêtes médias sont nécessaires, car cacher le menu complet et afficher un bouton de menu relève d’une décision concernant la structure de la page (cette règle est également divisée en deux) :
@media (max-width: 900px) {
.navigation {
display: none;
}
.menu-button {
display: block;
}
}
Les préférences de l’utilisateur relèvent d’une catégorie complètement différente. Rendre les animations moins intenses pour ceux qui ont demandé à leur système d’exploitation moins de mouvements n’a rien à voir avec un conteneur :
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms;
animation-iteration-count: 1;
}
}
Il s’agit d’une préférence d’environnement que seules les requêtes médias peuvent lire. L’objectif n’est pas d’éliminer les requêtes médias, mais simplement de cesser de les utiliser pour prendre des décisions concernant les composants.
Une approche en trois niveaux pour le CSS responsive
Dans une application basée sur des composants, il est utile de penser au stylisme responsive en trois niveaux.
Niveau 1 : réactivité globale avec des requêtes médias
Les requêtes médias gèrent les aspects qui concernent toute la page :
Page layout
Navigation
Global typography
Major structural changes
Application shell
Niveau 2 : réactivité des composants avec des requêtes de conteneur
Les requêtes de conteneur gèrent la mise en page interne des éléments autonomes :
Cards
Widgets
Panels
Reusable components
Design-system components
Dashboard modules
Niveau 3 : comportement fluide avec des fonctions et des unités
Lorsqu’aucun point de rupture fixe n’est nécessaire, laissez les valeurs s’échelonner continuellement grâce à des fonctions et des unités modernes :
clamp()
min()
max()
minmax()
cqi
cqw
Un encadré, par exemple, peut grandir avec son conteneur entre deux limites fixes :
.heading {
font-size: clamp(1.5rem, 3cqi, 3rem);
}
Collectivement, ces niveaux forment un système plutôt qu’un amas de correctifs basés sur des points de rupture.
Le véritable changement réside dans celui qui prend la décision
Il est tentant de résumer les requêtes de conteneur en « requêtes médias pour des éléments ». Cela est techniquement exact mais manque le point essentiel. Ce qui change, c’est le modèle de responsabilités. Dans le CSS responsive traditionnel, la page dicte en fait comment chaque composant se comporte :
Viewport
↓
Media Query
↓
Component
Avec les requêtes de conteneur, chaque composant s’oriente selon son propre conteneur :
Component Container
↓
Container Query
↓
Component
Les composants qui possèdent leurs propres règles de réponse sont plus faciles à réutiliser, à déplacer, à tester en isolation et à entretenir. Ce changement de responsabilité constitue l’avantage durable.
Une question à se poser pour chaque cas
Lorsque vous ne savez pas quel outil utiliser, demandez-vous si la décision de mise en page concerne la page ou le composant. Si elle concerne la page, utilisez une requête média. Si elle concerne l’espace alloué au composant, utilisez une requête de conteneur. Appliqué aux cas récurrents :
Should the sidebar disappear?
↓
Media Query
Should this card switch from horizontal
to vertical?
↓
Container Query
Should the navigation collapse?
↓
Media Query
Should this reusable widget change
its internal layout?
↓
Container Query
Points clés
- Les requêtes média décrivent la vue d’écran et l’environnement de l’utilisateur, ce qui les rend adaptées à la structure de la page, à la navigation, à la typographie globale ainsi qu’aux préférences telles que la réduction du mouvement.
- Les requêtes de conteneur décrivent l’espace reçu par un composant, ce qui les rend adaptées aux cartes, aux widgets, aux panneaux et aux composants de systèmes de design.
cqi et cqw, encadrées par clamp() avec des limites en rem, permettent une taille fluide sans compromettre les paramètres de taille du texte pour l’utilisateur.