Css
Senior
Quiz-Css-Senior
Bem
Itcss
Oocss
Container-Queries
Css-Layer
Cascade-Layers
Css-Houdini
Performance-Css
Accessibilite
Entretien-Css-Senior
Qcm-Css-Avance
📝
Entretien CSS Senior — Architecture et Performance
20 questions CSS niveau senior : BEM, ITCSS, CSS Houdini, containment, @layer, container queries, performances, accessibilité. Pour réussir un entretien développeur CSS Senior.
Banque de révision : les 55 questions corrigées
Voici l'intégralité des 55 questions de « Entretien CSS Senior — Architecture et Performance », chacune avec sa bonne réponse et son explication. Le quiz interactif ci-dessus en tire une sélection aléatoire à chaque tentative — utilisez cette liste complète pour réviser.
Explication :
BEM (Block Element Modifier) est une méthodologie de nommage :
.block, .block__element, .block--modifier. Avantages : sélecteurs plats (faible spécificité), auto-documentés, modulaires, évite les collisions de noms. Exemple : .card, .card__title, .card--featured.
Explique comment BEM résout le problème de spécificité en évitant les sélecteurs imbriqués. Mentionne les alternatives : OOCSS, SMACSS, Atomic CSS, et pourquoi on choisit l'un plutôt que l'autre.
Explication :
La propriété
contain indique au navigateur qu'un sous-arbre DOM est indépendant du reste. Valeurs : layout (layout interne isolé), style (styles compteurs isolés), paint (pas de peinture hors limites), size (taille indépendante du contenu). contain: content = layout + style + paint. Réduit le scope des recalculs.
Cas d'usage concret : un widget de commentaires avec
contain: content — si le DOM interne change, le navigateur ne recalcule que ce sous-arbre. Critique pour les performances des listes longues.
Explication :
C'est une différence fondamentale :
:where() a toujours une spécificité de 0, quelle que soit la complexité de ses arguments. :is() prend la spécificité de l'argument le plus spécifique. Ex : :is(#id, .class) a une spécificité d'ID. :where(#id, .class) a une spécificité de 0. :where() est idéal pour les resets CSS — styles de base facilement surchargeables sans utiliser !important. :is() est utile pour éviter la répétition de sélecteurs complexes sans perdre la spécificité.
Explication :
Les propriétés
transform et opacity peuvent être animées sur le thread compositor (GPU), séparément du thread principal JS. Les autres propriétés comme width, height, top, left déclenchent layout + paint sur le thread principal = jank. La règle d'or : animate transform and opacity only.
Mentionne le pipeline de rendu : JavaScript → Style → Layout → Paint → Composite. Animer transform/opacity saute les étapes Layout et Paint. Outils : Chrome DevTools → Performance pour identifier les frame drops.
Explication :
content-visibility: auto saute le rendu des éléments hors écran (gains de performance importants). Mais quand l'élément n'est pas rendu, sa taille est 0 — ce qui cause du layout shift (CLS). contain-intrinsic-size donne au navigateur une estimation de la taille pour maintenir le scroll cohérent.
Explication :
CSS Houdini expose le pipeline de rendu CSS aux développeurs. APIs clés : Paint API (dessiner dans une image CSS via Canvas), Layout API (créer des algoritmes de mise en page custom), Animation Worklet (animations sur le compositor), Typed OM (CSS Object Model typé, plus performant). Permet de créer des propriétés CSS custom avec logique.
La Paint API est la plus disponible aujourd'hui — elle permet de dessiner des backgrounds complexes (ex: triangles, patterns) qui s'adapten à la taille de l'élément, accessibles via
background: paint(mon-worklet).
Explication :
Les CSS logical properties remplacent les directions physiques par des directions logiques liées à la direction d'écriture.
margin-inline-start remplace margin-left en LTR et margin-right en RTL automatiquement. Autres exemples : block-size (= height), inline-size (= width), padding-block-start (= padding-top en LTR).
Essentielles pour l'internationalisation (i18n). Si tu builds pour des langues RTL (arabe, hébreu), utiliser les logical properties évite d'écrire des sélecteurs
[dir="rtl"] séparément.
Explication :
Un système de tokens robuste utilise deux niveaux : tokens primitifs (
--color-blue-500: #3b82f6) et tokens sémantiques (--color-action: var(--color-blue-500)). Les composants n'utilisent que les tokens sémantiques. Pour le dark mode, on redéfinit uniquement les tokens sémantiques dans @media (prefers-color-scheme: dark) ou via une classe.
Structure recommandée : categories (color, spacing, typography, shadow, border), puis tier (primitive → semantic → component). Les tokens peuvent être exportés depuis Figma via des plugins comme Tokens Studio.
Explication :
transform: translateZ(0) (ou translate3d(0,0,0)) est le "hack GPU" historique — il force la promotion de l'élément sur le thread compositor en créant un layer. Aujourd'hui, will-change: transform est la méthode officielle. Le hack est encore utilisé pour compatibilité mais crée un layer permanent (consomme de la mémoire GPU).
Explication :
Le Critical Rendering Path : 1) Parser HTML → DOM, 2) Parser CSS → CSSOM, 3) Combiner DOM + CSSOM → Render Tree, 4) Layout (calcul des tailles/positions), 5) Paint (pixels), 6) Composite. Le CSS est render-blocking : le navigateur ne peut pas afficher tant que tout le CSS n'est pas parsé. D'où l'importance du Critical CSS inliné et du
media sur les CSS non-critiques.
Optimisations : inliner le Critical CSS, charger le CSS non-critique avec
<link rel="preload" as="style"> + onload, utiliser media="print" pour différer puis changer en all.
Explication :
@layer (Cascade Layers) permet de définir des couches de cascade avec une priorité explicite. Exemple : @layer reset, base, components, utilities;. Les styles dans utilities l'emportent sur components, peu importe la spécificité. Révolutionne la gestion des overrides — plus besoin de !important pour les utilitaires.
Tailwind CSS v4 utilise @layer. Les styles hors couche ont la priorité la plus haute par défaut. Un style dans une couche déclarée en dernier bat un style dans une couche déclarée en premier, quelle que soit la spécificité.
Explication :
La meilleure approche : 1) Déclarer les tokens sur
:root (valeurs light). 2) Redéfinir les tokens dans @media (prefers-color-scheme: dark) ET dans une classe .dark-theme (pour toggle manuel). 3) Tous les composants utilisent uniquement les tokens. Avantage : changer le thème = modifier ~20 variables, pas des centaines de règles.
Pour la persistance du toggle manuel, sauvegarde la préférence en localStorage et applique la classe au
<html> avant le render (pas après, pour éviter le flash). Le sélecteur :root sur <html> permet d'éviter des conflits de spécificité.
Explication :
subgrid comme valeur de grid-template-columns ou grid-template-rows permet à un élément de grille d'adopter les tracks définis par la grille parent. Ses enfants peuvent alors s'aligner sur la grille grand-parent. Résout élégamment le problème d'alignement dans les cartes avec des éléments à des hauteurs différentes.
Cas d'usage classique : une grille de cartes dont les titres, corps et boutons doivent s'aligner entre les cartes. Avant subgrid, il fallait des hacks JS ou des hauteurs fixes.
Explication :
L'accessibilité CSS inclut :
:focus-visible (focus ring visible pour clavier, pas pour souris), @media (prefers-reduced-motion) (désactive animations pour les utilisateurs sensibles), contraste de couleurs (WCAG AA = 4.5:1), outline: none dangereux sans alternative, .sr-only pour masquer visuellement mais garder pour lecteurs d'écran, taille de texte minimum 16px.
Mentionne
:focus-visible vs :focus — utilise :focus-visible pour afficher l'outline uniquement lors de la navigation clavier, préservant l'UX souris tout en étant accessible.
Explication :
transform-origin définit le point de pivot des transformations (rotations, échelles). Défaut : center center. perspective-origin sur le conteneur perspective définit le point de fuite de la scène 3D — d'où "regarde" l'observateur. Ces deux propriétés combinent pour créer des effets 3D convaincants.
Explication :
Audit CSS complet : 1) Coverage (Chrome DevTools) → identifier le CSS inutilisé. 2) Performance panel → repérer les reflows coûteux. 3) Layers panel → détecter les layers GPU non justifiés. 4) Selector performance → éviter les sélecteurs universels (*) en combinaison avec descendants. 5) render-blocking CSS → inliner le critical, différer le reste.
Métriques clés : First Contentful Paint (FCP), Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS). Le CSS impact surtout FCP et CLS. PurgeCSS ou Tailwind's purge supprime le CSS inutilisé en production.
Explication :
prefers-reduced-motion: reduce cible les utilisateurs ayant activé la préférence de réduction de mouvement dans leur OS (ex: "Réduire le mouvement" sur macOS/iOS). Ces utilisateurs peuvent avoir des problèmes vestibulaires (vertiges), épilepsie, etc. Bonne pratique : désactiver ou ralentir les animations dans ce contexte.
Pattern recommandé : définir les animations par défaut, puis les désactiver dans la media query. Ex :
@media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }.
Explication :
OOCSS (Nicole Sullivan) pose deux principes : 1) Séparer la structure (layout, dimensions) de l'apparence (couleurs, bordures). 2) Séparer le contenant du contenu (éviter les sélecteurs contextuels comme
.sidebar .btn). OOCSS favorise des classes utilitaires réutilisables. BEM est plus prescriptif sur le nommage et l'organisation en blocks.
Tailwind CSS est philosophiquement proche d'OOCSS (classes utilitaires composables). BEM est plus adapté aux équipes qui préfèrent des composants encapsulés avec une nomenclature explicite.
Explication :
@supports (Feature Queries) permet de tester si le navigateur supporte une propriété CSS : @supports (display: grid) { .container { display: grid; } }. On peut aussi nier : @supports not (display: grid) { } ou combiner : @supports (display: grid) and (gap: 20px) { }. La base du Progressive Enhancement en CSS.
Explication :
Le CLS lié aux polices vient du fait que la police de remplacement a des métriques différentes. Solution moderne :
font-display: swap + descripteurs size-adjust, ascent-override, descent-override dans @font-face pour ajuster métriquement la police de remplacement. Résultat : quasi zéro CLS lors du swap.
L'outil "Fontaine" ou "next/font" génère automatiquement ces ajustements. C'est devenu une pratique Core Web Vitals critique pour les sites à fort trafic.
Explication :
aspect-ratio maintient un rapport largeur/hauteur défini. Si la largeur est 800px, la hauteur sera automatiquement calculée à 450px (800 × 9/16). Remplace avantageusement le vieux hack padding-top. Fonctionne aussi avec aspect-ratio: 1 pour un carré. Très utile pour les placeholders d'images et les vidéos responsives.
Explication :
Un BFC est un mini-layout indépendant. Il se crée avec :
float (non-none), position: absolute/fixed, display: inline-block/flex/grid/table/flow-root, overflow (non-visible), contain: layout/paint. Effets : contient ses flottants (clearfix), empêche le margin collapse avec ses enfants, évite le chevauchement avec des flottants sibling.
La méthode moderne pour créer un BFC sans effets secondaires est
display: flow-root. Comprendre les BFC est essentiel pour débugguer les problèmes de margin collapse et de clearfix.
Explication :
La valeur par défaut est
ease — l'animation démarre lentement, accélère, puis ralentit en fin. Les valeurs communes : linear (vitesse constante), ease-in (accélère), ease-out (décélère — naturel pour les sorties), ease-in-out, cubic-bezier() (courbe personnalisée). Pour les animations d'UI, ease-out est souvent le plus naturel.
Explication :
La méthode actuelle :
columns: 3; column-gap: 20px (CSS Multi-column). Les éléments s'empilent en colonnes verticales. Limitation : l'ordre de lecture est de haut en bas, pas de gauche à droite. La spec CSS Grid "masonry" (grid-template-rows: masonry) est en discussion mais pas encore standard. Pour un vrai masonry horizontal, JavaScript reste souvent nécessaire.
Mentionne le support expérimental de
grid-template-rows: masonry dans Firefox (flag). C'est une feature très attendue et un excellent sujet de conversation sur les CSS features modernes.
Explication :
isolation: isolate crée un nouveau stacking context SANS modifier d'autres propriétés visuelles (contrairement à opacity < 1, transform, etc.). Utile pour contrôler les z-index : un enfant avec mix-blend-mode ne blende qu'avec les éléments dans son stacking context. Aussi utile pour encapsuler les z-index d'un composant.
Explication :
La "Specificity Wars" : pour surcharger un style, on écrit un sélecteur encore plus spécifique, qui requiert encore plus de spécificité pour être surchargé, créant une escalade. Solutions : 1) BEM (sélecteurs plats, spécificité faible), 2)
@layer (cascade layers contrôlée), 3) Utilitaires à haute spécificité via @layer utilities, 4) Éviter les IDs comme sélecteurs CSS.
La règle d'or : maintenir la spécificité aussi basse que possible. Classes uniquement (0,0,1,0), pas d'IDs (0,1,0,0) dans les feuilles de style.
!important est le symptôme, pas la solution.
Explication :
mix-blend-mode contrôle comment les couleurs d'un élément se fondent avec ceux en dessous. multiply multiplie les valeurs RGB (0=noir, 1=transparent) — similaire à la transparence en impression. Autres valeurs utiles : screen (inverse de multiply), overlay, darken, lighten. Créer des effets de double exposition ou de texte découpé.
Explication :
Le Shadow DOM isole les styles. Pour styler depuis l'extérieur : 1)
::part(nom) cible des parties exposées explicitement (via l'attribut part="nom"). 2) ::slotted() cible les éléments projetés dans les slots. 3) Les CSS custom properties traversent le Shadow DOM — excellent pour le theming. 4) Adoptable Stylesheets (API moderne).
Les custom properties CSS sont le mécanisme de theming recommandé pour les Web Components. Elles traversent la frontière Shadow DOM, permettant un theming externe contrôlé.
Explication :
La valeur
auto dans une grille signifie que la colonne prend la taille de son contenu (similaire à min-content ou max-content selon le contexte). Contrairement à 1fr qui prend une fraction de l'espace disponible, auto est contraint par son contenu. C'est utile pour les colonnes d'icônes ou de labels courts.
Explication :
ITCSS (Harry Roberts) organise les fichiers CSS en couches de la spécificité la plus faible à la plus haute : Settings (variables) → Tools (mixins) → Generic (resets) → Elements (HTML tags) → Objects (patterns layout, OOCSS) → Components (UI spécifiques) → Utilities (overrides). Chaque couche ne surcharge que les couches précédentes. Idéal pour les grandes bases de code.
ITCSS se marie bien avec BEM pour les Components et des classes utilitaires pour les Utilities. C'est l'architecture derrière CSS Inuit (framework de Harry Roberts). Très pertinent pour les projets d'équipe de plus de 5 développeurs.
Explication :
min(a, b) retourne la valeur la plus petite parmi ses arguments. Ex : width: min(500px, 100%) — sur desktop (>500px), la largeur sera 500px ; sur mobile (
Explication :
Le pattern "CSS Custom Properties as API" : un composant définit ses propres variables avec des valeurs par défaut :
.btn { --btn-bg: blue; --btn-color: white; background: var(--btn-bg); color: var(--btn-color); }. Pour thématiser : .btn-red { --btn-bg: red; } ou depuis le parent : .card .btn { --btn-bg: var(--card-accent); }.
C'est la technique utilisée par des design systems comme Material Design Web Components. Les variables CSS peuvent aussi être modifiées via JavaScript :
element.style.setProperty('--btn-bg', '#f00').
Explication :
scroll-snap-type sur le conteneur et scroll-snap-align sur les enfants créent un comportement de "snap" au défilement — l'utilisateur scrolle et le viewport s'arrête sur des positions définies. Idéal pour les carousels et sliders en CSS pur, sans JavaScript. Valeur exemple : scroll-snap-type: x mandatory.
Explication :
@scope (.card) to (.card__footer) { .title { ... } } limite l'application des styles à un sous-arbre DOM précis (de .card jusqu'à .card__footer). Évite d'avoir à préfixer chaque sélecteur avec le nom du composant. Résout le problème des styles qui "fuient" entre composants imbriqués — plus besoin de BEM ou de nommage explicite dans certains cas.
C'est une feature CSS récente (2024).
@scope avec une limite (to) permet le "donut scoping" — styliser les éléments dans le scope sauf ceux dans la limite définie.
Explication :
overscroll-behavior: contain empêche le "scroll chaining" — quand on atteint la fin d'un conteneur scrollable enfant, le scroll ne se propage pas au parent. Très utile pour les modales, dropdowns, et sidebars avec scroll indépendant. none empêche aussi les effets de rebond (pull-to-refresh) sur mobile.
Explication :
Pour un monorepo : 1) Design tokens partagés comme package npm (variables CSS ou JSON). 2) CSS Modules avec namespace automatique (évite collisions). 3) Tailwind config partagée via preset. 4) Composants UI partagés (Storybook). La règle clé : les tokens sont partagés, l'implémentation peut diverger selon les besoins de chaque app.
Mentionne les build tools : Turborepo ou Nx pour le cache et l'orchestration. Les design tokens en TypeScript (Object as const) permettent l'autocomplétion et la vérification de types.
Explication :
Les compteurs CSS permettent une numérotation automatique.
counter-reset: section initialise le compteur. counter-increment: section l'incrémente. content: counter(section) l'affiche. Exemple : numérotation automatique des sections d'article ou des items de liste personnalisés sans modifier le HTML.
Explication :
Le paint convertit le render tree en pixels. Les propriétés déclenchant un repaint coûteux :
color, background, box-shadow, border-radius, outline, border-color. Pour optimiser : promouvoir les éléments animés sur des layers GPU (transform/opacity uniquement), utiliser contain: paint, éviter les shadows complexes sur de grandes zones.
Le panel Rendering dans Chrome DevTools (Paint flashing) visualise les zones repeintes. Si toute la page se colore en vert à chaque scroll, il y a un problème de repaint.
Explication :
:focus-within s'applique à un élément si lui-même OU n'importe lequel de ses descendants a le focus. Utile pour : surligner un formulaire entier quand un champ est actif, afficher un label flottant, mettre en valeur un groupe de contrôles. Exemple : .form-group:focus-within label { color: blue; }.
Explication :
Un CSS maintenable repose sur : 1) Architecture cohérente (ITCSS, BEM, Atomic). 2) Design tokens (single source of truth pour les valeurs). 3) CSS Linter (stylelint) pour forcer les conventions. 4) Suppression du CSS mort (PurgeCSS, Coverage DevTools). 5) Documentation des décisions (pourquoi ce hack, cette spécificité). 6) Refactoring régulier.
La dette CSS est insidieuse car CSS ne "casse" pas — les styles obsolètes continuent de fonctionner. Instaure une revue de code CSS et des critères d'acceptation clairs (pas d'ID dans les sélecteurs, pas de !important sans commentaire justificatif).
Explication :
Les Container Queries permettent de définir des styles selon la taille du conteneur parent de l'élément (et non du viewport). Un composant peut ainsi s'adapter à sa taille disponible, peu importe où il est placé dans la page. On déclare d'abord
container-type: inline-size sur le parent, puis @container (min-width: 400px) { ... }.
C'est une des features CSS les plus importantes de la décennie. Elle permet enfin de créer de vrais composants responsive — un bouton peut avoir une mise en page différente dans une sidebar étroite vs un layout large, sans JavaScript.
Explication :
Bonne pratique : définir les breakpoints dans un token (Sass variable, JS config, ou CSS custom property de référence), les nommer sémantiquement (sm, md, lg, xl), les documenter (640px = mobile landscape, 768px = tablet...). Outils : Sass
$breakpoints map + mixin, PostCSS custom media queries, ou la config Tailwind partagée.
Les "magic numbers" de breakpoints éparpillés dans le code rendent la maintenance cauchemardesque. Centralise et nomme — une seule source de vérité pour toute l'équipe.
Explication :
env() accède à des valeurs définies par le navigateur. Usage principal : padding-bottom: env(safe-area-inset-bottom) — essentiel pour les iPhones avec encoche/Dynamic Island (évite que le contenu soit coupé). Les safe-area-insets représentent les zones où l'interface iOS empiète sur le contenu.
Indispensable pour les PWA et les applications mobiles web. Ajoute
viewport-fit=cover dans le meta viewport pour activer le mode plein écran sur iOS, puis utilise env(safe-area-inset-*) pour les marges.
Explication :
Le print CSS dans
@media print contrôle l'apparence à l'impression. Propriétés clés : page-break-before/after/inside (ou break-before/after/inside), orphans/widows (min lignes seules en bas/haut de page), @page (marges, format, orientation). Masquer les navbars, footers, publicités. Utiliser des URLs de liens en contenu (a::after { content: " (" attr(href) ")"; }).
Explication :
::backdrop cible l'overlay créé derrière un élément en mode plein écran (:fullscreen), derrière un <dialog> ouvert, ou derrière un Popover API. Par défaut, c'est un fond noir semi-transparent. On peut le personnaliser : dialog::backdrop { background: rgba(0,0,0,0.5); backdrop-filter: blur(4px); }.
Explication :
grid-template-areas est idéal pour les layouts de page : grid-template-areas: "header header" "sidebar main" "footer footer". Chaque enfant est assigné via grid-area: header. C'est lisible, maintenable, et simple à responsive-ifier — sur mobile, on redéfinit les areas en colonnes simples.
C'est la façon la plus lisible de coder un layout de page complexe. La représentation ASCII des zones dans le CSS rend le layout auto-documenté. Montre que tu maîtrises l'outil principal de Grid.
Explication :
text-wrap: balance demande au navigateur de répartir équitablement le texte sur les lignes, évitant une dernière ligne avec un seul mot. Parfait pour les titres et sous-titres. text-wrap: pretty est similaire mais optimisé pour les paragraphes (évite les orphelins). Encore en déploiement (support partiel en 2024).
Explication :
CSS permet des micro-interactions avancées :
:hover + transition pour des effets de survol, :focus-visible pour l'accessibilité clavier, :active pour le feedback de clic, :checked + sélecteur adjacent pour des toggles sans JS, @keyframes + animation pour des effets de feedback. Le tout déclaratif et performant.
Pattern toggle pur CSS :
input[type="checkbox"] caché + label stylisé + input:checked ~ .element pour modifier des éléments frères. Accessible (keyboard, screen readers) sans une ligne de JS.
Explication :
view-transition-name identifie un élément pour les View Transitions API. Quand la page change (navigation SPA ou MPA), les éléments avec le même nom dans les deux vues sont animés via un morphing automatique. Ex : une carte produit qui "vole" vers la page détail. S'associe avec document.startViewTransition() en JS ou les navigations Chrome modernes.
Feature 2024 très impressionnante pour les SPA. Démo : dans Chrome, une même image sur deux routes différentes fait un morphing fluide sans une ligne d'animation CSS custom.
Explication :
Audit d'une base CSS héritée : 1) Coverage → % inutilisé. 2) Grep
!important → dette technique. 3) Grep #id dans CSS → risques de spécificité. 4) Profondeur de nesting → maintenabilité. 5) Valeurs répétées sans variable → opportunités de tokens. 6) Test pratique : ajouter une feature simple → combien d'endroits modifier ?
Le test "modifier la couleur primaire" est révélateur. Si tu dois toucher 50 fichiers → pas de tokens. Si tout change en modifiant une variable → bonne architecture. C'est le test le plus pratique en entretien pour montrer ta vision d'un CSS maintenable.
Explication :
color-scheme déclare quels schémas de couleur supporte l'élément (ou la page). Quand défini sur :root, il permet au navigateur d'adapter les éléments natifs (scrollbars, checkboxes, inputs, select) au thème clair/sombre de l'OS. Sans cette propriété, même avec un dark mode complet, les scrollbars restent blancs.
Explication :
Sans
@layer, surcharger un framework CSS nécessitait souvent une spécificité plus élevée ou !important. Avec @layer, le framework déclare ses styles dans une couche (@layer framework). Les styles utilisateur hors couche ont automatiquement la priorité — quelle que soit leur spécificité. Tailwind v4 adopte cette approche.
Explication :
filter: blur(4px) floute l'élément lui-même et son contenu. backdrop-filter: blur(4px) floute ce qui est visible derrière l'élément (effet "verre dépoli" / frosted glass). Pour que backdrop-filter soit visible, l'élément doit avoir une transparence (background: rgba(255,255,255,0.2)). backdrop-filter est plus coûteux en GPU.
Explication :
Atomic CSS (Tailwind, UnoCSS) : chaque classe fait une seule chose (
text-blue-500, p-4). Le style est dans le HTML. CSS final très petit (purge). BEM/composants : le HTML est sémantique, le style est dans le CSS. Plus verbeux côté CSS. En production aujourd'hui, Tailwind domine pour sa vitesse de développement, mais BEM reste pertinent pour les design systems complexes.
Ne prends pas position tranchée — dis que tu utilises les deux selon le contexte. Tailwind pour les apps, BEM pour les librairies de composants distribuées (où le consommateur doit pouvoir surcharger facilement).
Explication :
minmax(200px, 1fr) définit une colonne dont la largeur est entre 200px minimum et 1fr maximum. La colonne ne sera jamais plus petite que 200px mais peut grandir pour occuper l'espace disponible proportionnellement. Pattern classique avec repeat(auto-fill, minmax(200px, 1fr)) pour une grille responsive sans media queries.