CSS Container Queries (ou "requêtes de conteneur" ?) permettent d'appliquer des styles à un élément en fonction des propriétés de son conteneur, généralement sa taille.
Il s'agit d'un mécanisme complémentaire aux historiques Media Queries qui, eux, détectent les caractéristiques de l'ensemble de la fenêtre ou de l'écran du périphérique.
Usage et intérêt
Les Media Queries représentent la première réponse proposée par le W3C pour s'adapter à tous les nouveaux "device intelligents", friands de Web, qui débarquent autour des années 2008-2010 (l'iPhone date de 2007) et qui préparent à la naissance du Responsive Webdesign.
Pour la petite histoire, les premiers brouillons de spécifications des Media Queries datent de…2001 mais le véritable essor de cette fonctionnalité attendra 2010 avec les premières implémentations des navigateurs.
Les Container Queries introduisent un nouveau palier dans le Responsive Webdesign en apportant une souplesse jusqu'alors inatteignable : tandis que les Media Queries ne détectent que l'ensemble du périphérique, les Container Queries permettent d'interroger le parent (ou ancêtre) d'un composant, bien plus proche et pertinent.
À l'heure où l'intégration se conçoit de plus en plus de manière atomique, en isolant chacun des composants, il devient de plus en plus cohérent de styliser ces composants en vertu de leur environnement direct plutôt que de raisonner à l'échelle de la fenêtre entière du navigateur. Les Container Queries sont parfaitement conçues dans cette optique.
L'extrait ci-dessous montre que la syntaxe entre les Media Queries et les Container Queries est très similaire :
/* Media Query (on détecte la largeur de la fenêtre) */
@media (min-width: 640px) {
/* ici les styles appliqués */
}
/* Container Query (on détecte la largeur du conteneur) */
@container (min-width: 640px) {
/* ici les styles appliqués */
}
Support navigateurs
Poursuivons sur les bonnes nouvelles : les propriétés de Container Queries sont supportées par une large majorité des navigateurs récents, comme en témoigne la ressource CanIUse, comme en témoigne la capture suivante. Elles sont donc déjà utilisables en production, moyennant quelques ajustements sur certains périphériques mobiles par exemple.
Container Query : en pratique
Appliquer des styles selon uneé Container Query se déroule en deux temps :
- Nous devons identifier qui est le conteneur à interroger en créant un "contexte de confinement"
- Nous pouvons tester les conditions via
@container
(syntaxe quasiment identique à@media
)
Déclarer qui est le conteneur à interroger
Pour identifier le conteneur que nous testerons, il nous faut créer un contexte de confinement (rassurez-vous, rien à voir avec la douloureuse période de l'an 2020) à l'aide de la propriété container-type
dont les valeurs possibles sont inline-size
, size
, ou normal
:
inline-size
: la condition porte sur la dimension inline (synonyme de largeur dans la majeure partie des cas)size
: la condition porte sur les dimensions inline et block en même temps (horizontale et verticale)normal
: la condition ne peut pas porter sur la dimension de l'élément (mais il est toutefois possible de cibler ses styles)
Prenons comme exemple un composant .card
dont les styles dépendent de la largeur de son parent .card-container
:
<div class="card-container">
<article class="card">
ici le contenu d'une card
</article>
</div>
/* On crée un contexte de confinement sur .card-container */
/* Et on testera sa largeur */
.card-container {
container-type: inline-size;
}
Note : Le conteneur n'est pas forcément le parent direct, il peut s'agir de n'importe quel ancêtre de l'élément à modifier.
Interroger le conteneur via @container
À présent que notre conteneur est identifié, nous pouvons l'interroger afin de connaître ses états (taille, ratio, orientation) et appliquer des styles sur ses descendants :
aspect-ratio
: il s'agit du ratio entre la largeur et la hauteur du conteneur (ex. "16/9")block-size
: il s'agit de la dimension "block" (généralement synonyme de hauteur, mais dépend de l'orientation du conteneur)height
: désigne la hauteur du conteneur, quelle que soit son orientationinline-size
: il s'agit de la dimension "inline" (généralement synonyme de largeur, mais dépend de l'orientation du conteneur)orientation
: c'est l'orientation du conteneur (valeurslandscape
ouportrait
)width
: désigne la largeur du conteneur, quelle que soit son orientation
Exemple :
/* je teste si le conteneur a une largeur supérieure ou égale à 640px */
@container (min-width: 640px) {
.card {
...
}
}
Nommer le conteneur
Les spécifications prévoient de conférer un nom personnalisé au conteneur à interroger. Cette possibilité offre la perspective très intéressante de pouvoir cibler un ancêtre qui ne serait pas forcément le premier rencontré dans la branche.
Ce nom est donné grâce à la propriété container-name
. On pourra ensuite cibler ce conteneur spécifique au sein de la règle @container
:
/* On crée un contexte de confinement sur .card-container */
/* Et on le nomme "product" */
.card-container {
container-type: inline-size;
container-name: product;
}
/* Je teste si "product" a une largeur supérieure ou égale à 640px */
@container product (min-width: 640px) {
.card {
...
}
}
Syntaxe range et and / or
Une évolution récente (mais déjà très bien supportée) des Media Queries autorise une syntaxe dite "range syntax" bien plus intuitive pour tout le monde.
Cette "range syntax" est également adoptée au sein des Container Queries et facilite grandement la lecture :
/* version "à l'ancienne" */
@container (min-width: 640px) {
.card {
...
}
}
/* version "moderne" */
@container (width >= 640px) {
.card {
...
}
}
Les spécifications offrent également la possibilité d'enrichir et de combiner les requêtes via les mots-clés and
, or
et not
:
@container (width > 400px) and (height > 400px) {...}
@container (width > 400px) or (height > 400px) {...}
@container not (width < 400px) {...}
Nouvelles unités responsive
De nouvelles unités de mesure CSS ont été ajoutées lorsque des styles sont appliqués à l'aide de Container Queries.
Ces unités permettent de définir les dimensions des composants en fonction de l'espace disponible au sein de leur conteneur :
cqw
: 1% de la largeur du conteneurcqh
: 1% de la hauteur du conteneurcqi
: 1% de la dimension inline du conteneurcqb
: 1% de la dimension block du conteneurcqmin
: la plus petite valeur entrecqi
etcqb
cqmax
: la plus grande valeur entrecqi
etcqb
Dans l'exemple qui suit, les styles suivants seront appliqués si le conteneur a une largeur entre 320px et 640px : une grille de deux colonnes est générée sur .card
, la première colonne a une largeur de 20% du conteneur et la seconde occupe l'espace restant. La taille de police de .card-title
est relative à la largeur du conteneur avec un valeur minimale de 1em
:
@container (320px <= width <= 640px) {
.card {
display: grid;
grid-template-columns: 20cqw 1fr;
}
.card-title {
font-size: max(1em, 10cqw);
}
}
Aller plus loin : style queries
Bien que la peinture des Container Queries soit encore toute fraîche, une évolution de ce mécanisme est déjà en préparation : les Style Container Queries !
Cette évolution est encore expérimentale et son support très partiel, mais son principe est déjà révolutionnaire : il sera possible de cibler un conteneur selon la valeur calculée de l'une de ses propriétés, voire d'une propriété personnalisée (custom property) en CSS :
@container style(position: relative) {
.card { color: hotpink; }
}
@container style(--theme: dark) {
.card { color: hotpink; }
}
Découvrez-en plus sur ce sujet palpitant grâce à l'article de Ahmad Shadeed
Ressources
Pour finir sur ce très vaste sujet, voici quelques liens pour aller encore plus loin dans votre veille technologique :
- Documentation de MDN : https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries
- Awesome Container Queries : https://github.com/sturobson/Awesome-Container-Queries
- CSS Container Queries guide : https://blog.logrocket.com/css-container-queries-guide/
- Container style queries : https://ishadeed.com/article/css-container-style-queries/
- Démo Cactus (Una Kravets) : https://codepen.io/una/full/mdOgyVL
- Démo Card : https://codepen.io/alsacreations/pen/dyQxERW
- Démo Bouton : https://codepen.io/alsacreations/pen/gOQVJRe
Commentaires
Je les utilise depuis quelques mois déjà... J'ai un problème avec les container queries lorsque je les imbriques les uns les autres, avec pourtant un conteneur nommé. J'en parlerais à l'occasion sur le forum.
@Olivier C : Ah oui le sujet m'intéresse aussi en effet.
Meaculpa : mon problème ne provenait pas des container queries mais des variables CSS que j'utilisais et qui influençaient sur la cascade si imbrication des éléments HTML. Au final je n'ai pas rencontré de problème avec cette règle autre que son support limité pour l'instant.
L'arrivée de cette règle fait partie de l'une des plus importante évolution de CSS de ces dernières années.