AccueilClientsExpertisesBlogOpen SourceJobsContact

22 juin 2023

CSS Containers Queries avec Tailwind

6 minutes de lecture

CSS Containers Queries avec Tailwind

Introduction 🌟

Le design responsive a changé notre façon de concevoir des sites web, en nous obligeant à les adapter dynamiquement en fonction de la taille de l'écran et des comportements des utilisateurs. Les media queries ont joué un rôle crucial dans cette transformation, en nous permettant d'appliquer des styles CSS en fonction des dimensions du viewport.

Cependant, l'évolution des frameworks JavaScript tel que ReactJS et des composants réutilisables a mis en évidence les limitations des media queries. Nous avons parfois besoin de moyens plus précis pour appliquer des styles aux composants individuels, en fonction de leurs contextes plutôt que de la taille de l'écran.

C'est là que les container queries entrent en jeu. Elles nous permettent d'interroger les informations de style d'un conteneur spécifique, telles que sa largeur et sa hauteur, et d'appliquer des règles CSS en conséquence.

Dans cet article, nous allons plonger dans les container queries, découvrir comment et quand les utiliser, les avantages qu'elles offrent pour créer des interfaces web modulaires et leurs implémentations dans Tailwind. 🚀

Comment utiliser les container queries ? 📦

Définir le container

Dans un premier temps il faut définir un container. Ce container est un élément HTML qui va servir de référence pour les container queries. Nous pourrons alors définir des règles applicables à tous ses enfants en fonction de sa taille.

.container {
  container-type: inline-size;
  container-name: myContainer;
}

On utilisera inline-size dans la grande majorité des cas en tant que type de container.

La propriété container-type permet de définir le type de container. Les containers queries furent d'abord proposées avec la propriété contain. C'est est une propriété CSS assez complexe mais pour faire simple elle permet d'indiquer au navigateur que l'élément et ses descendants sont considérés comme indépendants de l'arborescence du document. Cela offre potentiellement des avantages en termes de performances. Cependant il y'a eu une révision de cette spécification, et maintenant on utilise container-type pour définir le type de container.

Si on le souhaite, on peut aussi utiliser la propriété raccourcie container comme ceci:

.container {
  /* combinaison de : container-name / container-type */
  container: myContainer / inline-size;
}

Spécifier notre règle

On a défini notre container, maintenant on peut spécifier une règle dans un contexte spécifique de ce dernier en utilisant @container.

Ici on spécifie une règle qui ne s'applique uniquement si la largeur de notre container est supérieur à 700px.

@container myContainer (min-width: 700px) {
  .card {
    /* '.card' est un enfant de 'myContainer' */
    font-size: 2em;
  }
}

Pour mieux comprendre comment elle fonctionne voici une démo très simple des container queries:

Les unités de container

Lorsqu’on applique des styles à un container à l'aide de container queries, on peut utiliser des unités de taille de container. Ces unités spécifient une longueur relative aux dimensions d'un container:

  • cqw: 1% de la largeur d'un container
  • cqh: 1% de la hauteur d'un container
  • cqi: 1% de la taille inline d'un container
  • cqb: 1% de la taille block d'un container
  • cqmin: La plus petite valeur de cqi ou cqb
  • cqmax: La plus grande valeur de cqi ou cqb

Quand utiliser ces queries ? 🤔

Elles sont très utiles quand on veut réutiliser un composant dans plusieurs contextes différents dans le même viewport.

Dans ce cas-là on aurait besoin de dire au navigateur de ne pas se préoccuper de la largeur du viewport mais plutôt de se fier à la largeur du container de notre composant.

Prenons un exemple concret qui pourrait servir. Nous avons une page de blog avec beaucoup d’articles, disposés dans des grids, dans des sidebars et différents layouts. On utilise le même composant "Article" à travers toute notre page. Notre composant doit donc être responsive, ce qui nous donne:

Example de composant responsive avec les CSS container queries

Maintenant mon composant sera responsive en fonction du container dans lequel il se trouve. Tout en utilisant le même composant je pourrais donc avoir des pages avec ces différents “états” du composant selon l’endroit où il se situe.

Example d'UI avec l'utilisation d'un composant responsive

Les cas d'usage sont nombreux, mais je vous partage un dernier petit example pour la route:

Ici nous avons un composant de pagination, qui pourrait être utilisé dans plusieurs contextes différents. Il s'adaptera à la largeur de son container pour afficher l'UI la plus adaptée.

Les container queries avec Tailwind 🌬

Les container queries ont récemment fait leur apparition dans les versions ≥ 3.3.2 de Tailwind.

Elles ne font pas encore partie du core et sont disponible uniquement en utilisant le plugin @tailwindcss/container-queries. Il vous faudra donc installer ce plugin pour pouvoir les utiliser.

Elles ne supportent que les règles sur la largeur maximale (max-width) pour l’instant, mais c’est déjà amplement suffisant pour beaucoup de cas d’usage. Les container queries dans Tailwind ont une syntaxe très similaire à celle des media queries à la différence que l’on préfixe notre règle avec @....

Définir le container avec Tailwind

Pour définir un container avec Tailwind il suffit tout simplement d'ajouter la classe @container

<div class="@container">
  <div>
    <!-- ... -->
  </div>
</div>

Spécifier notre règle avec Tailwind

Tailwind met à disposition 11 échelles pré-définies de max-width allant de xs à 7xl. Mais il est possible de les configurer si nécessaire dans le fichier tailwind.config.js

NameValue
xs20rem
sm24rem
md28rem
lg32rem
xl36rem
2xl42rem
3xl48rem
4xl56rem
5xl64rem
6xl72rem
7xl80rem

Pour des valeurs plus arbitraires, on peut aussi préciser une valeur absolue avec la syntaxe @[...]

<div class="@container">
  <!-- Valeur pré-définie -->
  <div class="m-2 @md:m-4">
    <!-- ... -->
  </div>
  <!-- Valeur absolue -->
  <div class="block @[618px]:flex">
    <!-- ... -->
  </div>
</div>

Cas d’usage: composant Article avec Tailwind 📰

Testons dans un cas pratique les containers queries avec Tailwind.

On imagine une page d’accueil de blog avec une dizaine d’articles disposés dans une grille.

Chaque article possède une image, un titre et une catégorie.

On va d’abord créer notre composant article seul, dans son plus petit container. Puis lui ajouter des containers queries pour les containers plus grands, autant qu’en nécessite notre design.

Cela donne quelque chose comme ceci:

export default function Article({ category, title, imageUrl, className }: Props) {
  return (
    <article className="shadow-lg rounded-lg @sm:rounded-2xl relative overflow-hidden flex flex-row @sm:flex-col cursor-pointer group h-auto @2xl:h-[300px]">
      <header className="hidden @xs:flex flex-1 relative z-10 w-24 @sm:w-full @sm:h-auto @2xl:h-full overflow-hidden">
        <Badge category={category} />
        <span className="absolute z-10 left-0 top-0 right-0 bottom-0 bg-black opacity-10"></span>
        <img
          src={imageUrl}
          alt="An preview of the article"
          className="w-auto h-full @sm:w-full @sm:h-40 @2xl:h-full object-cover object-center @2xl:group-hover:scale-110 @2xl:transition-transform @2xl:duration-500 @2xl:ease-in-out"
        />
      </header>
      <div className="flex flex-[3] flex-col gap-3 @sm:gap-6 justify-start p-3 @sm:p-5 rounded-b-2xl overflow-hidden z-20 @2xl:absolute @2xl:bg-transparent @2xl:left-0 @2xl:right-0 @2xl:bottom-0 @4xl:h-full @4xl:justify-center @4xl:items-center">
        <p className="text-ellipsis overflow-hidden whitespace-nowrap @sm:whitespace-normal text-base @sm:text-xl @2xl:text-2xl @4xl:text-4xl @4xl:text-center font-bold w-auto @sm:w-[15ch] @2xl:w-[25ch] max-w-[100%] text-black @2xl:text-white @2xl:pointer-events-none">
          {title}
        </p>
        <button
          type="button"
          className="rounded-md bg-indigo-50 px-2 py-1 @sm:px-3 @sm:py-2 text-xs @sm:text-sm font-semibold text-indigo-600 shadow-sm hover:bg-indigo-100 mr-auto @2xl:hidden"
        >
          Read Article
        </button>
      </div>
    </article>
  )
}

Pas super lisible mais c’est le principal défaut des librairies de nomination fonctionnelle comme Tailwind.

Une fois que notre composant est responsive dans ces différents contextes, on le teste dans chacune des grids. Ici on a repris dans les grandes lignes les trois grids de notre exemple du début:

  • mobile
  • tablet
  • desktop

Voici le résultat 🤓

Conclusion 🎉

En conclusion, bien que les containers queries offrent des possibilités intéressantes, leur utilisation dans le cadre de Tailwind présente certaines limites.

En effet, les container queries sont généralement utilisés dans des scénarios spécifiques où des valeurs absolues et arbitraires sont nécessaires, ce qui peut rendre leur utilisation moins adaptée aux librairies à classes utilitaires comme Tailwind. On peut vite se retrouver avec des classes qui perdent en lisibilité et en maintenabilité dans des cas d'usage plus complexes.

Cependant, ces limites vis-à-vis de Tailwind ne se posent que dans des scénarios complexes mais ne sont pas un problème pour des cas d'usage plus simples.

De plus, il est important de noter que ces limites ne remettent pas en question l'utilité des containers queries en général. Elles restent une option puissante pour créer un design responsive et réactif dans d'autres contextes et pour des besoins spécifiques.

Ressources 📚

18 avenue Parmentier
75011 Paris
+33 1 43 57 39 11
hello@premieroctet.com

Suivez nos aventures

GitHub
Twitter
Flux RSS

Naviguez à vue