Préparation d'entretien 100% Gratuit angularforall.com

Entretien Tailwind CSS Senior — Architecture, Plugins, v4

Tailwind Tailwindcss Senior Tailwind-V4 Tailwind-Plugins Design-Tokens Shadcn Cva Oklch Container-Queries Rtl-Tailwind Accessibilite-Tailwind Tailwind-Architecture Entretien-Tailwind-Senior
Sénior 🔀 Mixte 20 questions ⏱ 15 min
📝

Entretien Tailwind CSS Senior — Architecture, Plugins, v4

20 questions Tailwind niveau senior : Tailwind v4, OKLCH, plugins custom, design tokens, RTL, accessibilité, container queries, shadcn/ui, performance, migration legacy.

20 questions ⏱ ~15 min Niveau Sénior

Partager

Banque de révision : les 60 questions corrigées

Voici l'intégralité des 60 questions de « Entretien Tailwind CSS Senior — Architecture, Plugins, v4 », 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.

  • Suppression du JIT
  • Configuration CSS-first via @theme et @import "tailwindcss", moteur Oxide en Rust, OKLCH par défaut (bonne réponse)
  • Suppression du dark mode
  • Plus de support Node.js
Explication : Tailwind v4 (2024–2025) introduit : (1) config CSS-first dans le fichier CSS via @theme { --color-brand: ...; }, @import "tailwindcss" remplace les 3 directives ; (2) moteur Oxide (Rust + LightningCSS) — build 5–10× plus rapide ; (3) espace OKLCH pour les couleurs (plus perceptuellement uniforme) ; (4) support natif des Cascade Layers, container queries, :has(), color-mix().
En entretien : tailwind.config.js reste utilisable en v4 via @config "./tailwind.config.js", donc migration progressive possible.

  • Écrire une classe CSS dans un fichier séparé
  • Utiliser plugin(({ addUtilities }) => { addUtilities({ '.scrollbar-thin': { ... } }) }) (bonne réponse)
  • Modifier theme.utilities
  • Impossible sans fork de Tailwind
Explication : L'API plugin officielle : const plugin = require('tailwindcss/plugin'); module.exports = { plugins: [ plugin(({ addUtilities }) => { addUtilities({ '.scrollbar-thin': { 'scrollbar-width': 'thin' }, '.scrollbar-none': { 'scrollbar-width': 'none' } }); }) ] }Les méthodes utiles : addUtilities, addComponents, addBase, matchUtilities (avec valeurs dynamiques), addVariant.
Avec matchUtilities, tu peux faire scrollbar-{couleur} qui accepte n'importe quelle couleur du thème, comme un utility natif.

  • Économie de bytes
  • Support automatique LTR/RTL (Right-to-Left) sans dupliquer les classes (bonne réponse)
  • Compatibilité IE11
  • Aucun, c'est une mode
Explication : ms-4 (margin-inline-start) = margin-left: 1rem en LTR mais margin-right: 1rem en RTL automatiquement. Idem me-*, ps-*, pe-*, start-*, end-*, border-s-*, border-e-*, text-start, text-end. Indispensable pour les apps i18n (arabe, hébreu, persan).
Pattern : utilise ps/pe/ms/me par défaut au lieu de pl/pr/ml/mr pour rendre toute la codebase RTL-ready dès le début.

  • @config "./tailwind.config.js"; (bonne réponse)
  • @import "tailwind.config.js";
  • @use "config";
  • @require config;
Explication : @config permet de continuer à utiliser un tailwind.config.js classique en v4, sans devoir tout migrer vers la config CSS-first. Pratique pour les migrations progressives.

  • Dupliquer la config par marque
  • Utiliser des CSS variables comme tokens (--color-primary) que Tailwind référence, et changer leurs valeurs selon la marque (data-attribute ou class root) (bonne réponse)
  • Forker Tailwind
  • Charger 2 fichiers Tailwind différents
Explication : Pattern moderne : :root { --color-primary: 220 90% 50%; } [data-theme="acme"] { --color-primary: 0 80% 60%; } // config colors: { primary: 'hsl(var(--color-primary) / <alpha-value>)' }Une seule build Tailwind, switch de thème par classe ou attribut. C'est la base de shadcn/ui, Radix, Vercel Design System.
Tailwind v4 supporte nativement @theme inline et CSS vars en first-class — le pattern devient trivial.

  • addUtilities
  • matchUtilities (bonne réponse)
  • addVariant
  • addComponents
Explication : matchUtilities mappe un utility sur un set de valeurs : matchUtilities({ 'text-shadow': (value) => ({ textShadow: value }) }, { values: theme('textShadow') });Génère text-shadow-sm, text-shadow-md... + accepte la syntaxe arbitraire text-shadow-[2px_2px_red].

  • Impossible sans modifier le core
  • Utiliser addVariant('third', '&:nth-child(3)') dans un plugin (bonne réponse)
  • Définir variants: { third: true }
  • Utiliser uniquement la syntaxe arbitraire
Explication : addVariant('third', '&:nth-child(3)') dans un plugin, et third:bg-red-500 devient utilisable. matchVariant permet aussi des variants paramétrés : matchVariant('nth', (value) => `&:nth-child(${value})`) → utilisable comme nth-3:bg-red.
Utile en pratique pour data-[state=open]:, aria-[disabled]:, group-data-[state=open]:... — Headless UI/Radix s'en servent intensivement.

  • data-[state=open]: (bonne réponse)
  • data-state-open:
  • has-data:
  • attribute:state=open
Explication : Tailwind v3.2 introduit les attribute selectors arbitraires : data-[state=open]:bg-blue-500, aria-[expanded=true]:rotate-180, data-[orientation=vertical]:flex-col. Indispensable pour styler les composants Radix/Headless UI.

  • Jamais, Tailwind est toujours mieux
  • Quand l'équipe préfère écrire du CSS sémantique scoped, ou pour des composants avec animations CSS très complexes ou de la logique conditionnelle CSS dense (bonne réponse)
  • Toujours pour des SPA
  • Pour la performance
Explication : Tailwind brille pour les apps avec design system cohérent et un grand nombre de composants. CSS Modules reste pertinent quand : (1) animations CSS complexes (keyframes longs, multistep), (2) styles très spécifiques peu réutilisables, (3) équipe historique CSS-first, (4) contraintes de bundle ultra-serrées (rares). Les deux peuvent cohabiter dans un même projet sans conflit.
Bonne pratique : Tailwind pour 90% du UI, CSS classique pour les exceptions complexes (graphiques, transitions multi-étapes, print styles).

  • has-[input:checked]: (bonne réponse)
  • parent-of:
  • contains:
  • with:
Explication : has-[selector]: compile en :has(...). Permet de styler un parent en fonction d'un descendant. Exemple : has-[input:checked]:bg-blue-100 = applique un fond bleu si l'élément contient un input coché. Compatible navigateurs modernes (depuis 2023).

  • Il fournit des composants packagés à installer via npm
  • Il propose des composants copy-paste dans ton repo, basés sur Radix UI + Tailwind, donc 100% modifiables sans dépendance (bonne réponse)
  • Il remplace Tailwind
  • Il génère le CSS automatiquement
Explication : shadcn/ui n'est pas une lib, c'est un générateur : npx shadcn add button copie le composant dans ton repo, basé sur Radix UI (logique a11y) + Tailwind (style) + cn() helper (clsx + tailwind-merge). Tu modifies librement, pas de version coincée par une dépendance externe. Devenu standard de fait sur les apps Next.js modernes.
Comprendre le pattern cva (class-variance-authority) que shadcn utilise : déclaration des variants en TypeScript avec types autocomplétés.

  • cn() (helper standard shadcn/ui) (bonne réponse)
  • twjoin()
  • tailwindCombine()
  • mergeClasses()
Explication : import { clsx } from 'clsx'; import { twMerge } from 'tailwind-merge'; export function cn(...inputs) { return twMerge(clsx(inputs)); }clsx assemble conditionnellement, twMerge résout les conflits Tailwind (ex: p-2 + p-4 → garde p-4). Le helper cn() est devenu un de facto standard de l'écosystème.

  • Désactiver Tailwind
  • (1) Restreindre content aux fichiers nécessaires, (2) éviter safelist permissive, (3) éviter les classes construites dynamiquement, (4) utiliser le moteur Oxide v4 ou JIT v3, (5) extraire les composants répétés via @apply ou des composants framework (bonne réponse)
  • Charger Tailwind via CDN
  • Activer toutes les variants
Explication : À grande échelle, le CSS final reste petit (souvent < 30 Ko gzipped) si la config est saine. Pièges principaux : safelist regex trop permissive qui regénère des milliers de classes ; theme sans extend qui force la régénération ; classes construites dynamiquement ('bg-' + color) invisibles au scanner. Le moteur Oxide (v4) accélère le build de 5–10×.
Outil de debug : npx tailwindcss --content './src/**/*' -o out.css --minify et inspecter out.css pour voir ce qui est généré.

  • scheme-dark (bonne réponse)
  • color-scheme-dark
  • dark-scheme
  • scheme-only-dark
Explication : scheme-dark et scheme-light appliquent color-scheme, qui affecte les UI natives du navigateur (scrollbars, form controls, autofill). À combiner avec dark mode quand on veut une cohérence totale.

  • supports-[backdrop-filter]: (bonne réponse)
  • feature-[backdrop-filter]:
  • can-[backdrop-filter]:
  • has-feature-backdrop:
Explication : supports-[property:value]: compile en @supports (property: value) { ... }. Exemple : supports-[backdrop-filter]:backdrop-blur-md n'applique le flou que si le navigateur le supporte. Excellent pattern de progressive enhancement.

  • Copier-coller la config
  • Créer un preset partagé : un fichier de config exporté comme package, importé via presets: [require('@org/tailwind-preset')] (bonne réponse)
  • Toujours réécrire de zéro
  • Impossible
Explication : Pattern monorepo : presets est un tableau de configs Tailwind héritées. Chaque app peut avoir son propre tailwind.config.js qui étend le preset commun. Permet de partager design tokens (couleurs, fonts, spacings) tout en autorisant overrides locaux. Idéal pour Nx, Turborepo, Lerna.
Les presets s'empilent : preset A → preset B → config app — chaque niveau peut override le précédent.

  • not-first: (bonne réponse)
  • except-first:
  • without-first:
  • :not-first
Explication : Depuis v3.4, les not-* variants sont natifs : not-first: = :not(:first-child), not-last:, not-disabled:, not-checked:... Pratique pour styler tous sauf un. Exemple : not-last:border-b = bordure sauf sur le dernier.

  • Tester manuellement à chaque release
  • Combiner Storybook (catalogue de composants) + Chromatic ou Percy (visual regression tests automatisés sur PR) (bonne réponse)
  • Tests unitaires uniquement
  • Tailwind se teste tout seul
Explication : Storybook documente chaque variant de composant. Chromatic (de Storybook) ou Percy/Loki capturent des screenshots et détectent les régressions visuelles sur chaque PR. Sur un projet Tailwind avec design system, c'est le filet de sécurité indispensable contre les régressions de design tokens (changer une couleur peut toucher 200 composants).
Combo classique : Storybook + Chromatic + Playwright pour les tests d'intégration → couvrent visuel, comportement, accessibilité.

  • view-transition-name-[card]
  • [view-transition-name:card]
  • Aucune classe native — utiliser style ou ajouter via plugin/arbitrary (bonne réponse)
  • vt-card
Explication : view-transition-name n'a pas d'utility natif. Solutions : (1) syntaxe arbitraire CSS via plugin custom matchUtilities({ 'vt-name': v => ({ viewTransitionName: v }) }), (2) style={{ viewTransitionName: 'card' }} en React, (3) classe arbitraire via [view-transition-name:card]. La View Transitions API ouvre des animations spectaculaires entre routes.

  • Aucun compromis
  • Pour : reset cohérent qui élimine les différences inter-navigateurs. Contre : peut casser un projet existant qui s'appuie sur les marges natives des h1, ul, p... (bonne réponse)
  • Il dégrade les performances
  • Il est obsolète
Explication : Preflight (basé sur modern-normalize) reset agressivement : marges 0, listes sans bullets, headings sans poids, etc. Avantage : tu pars d'une base propre, le design vient des classes Tailwind. Inconvénient : intégrer Tailwind dans un site WordPress ou un CMS existant peut casser le rendu. Solution : corePlugins: { preflight: false } ou utiliser @tailwindcss/typography via prose sur les zones rich-text.
Astuce : sur un projet hybride, scope Tailwind à un wrapper (.app) via PostCSS plugin tailwindcss-scoped-preflight.

  • cva est un utility qui définit les variants d'un composant en TypeScript avec types et autocomplete : cva('btn', { variants: { size: { sm: '...', lg: '...' } } }) (bonne réponse)
  • C'est un fork de Tailwind
  • Une lib obsolète
  • Un préfixe Tailwind
Explication : Pattern shadcn/ui : const button = cva('inline-flex rounded font-medium', { variants: { intent: { primary: 'bg-blue-500', secondary: 'bg-gray-200' }, size: { sm: 'px-2 py-1 text-sm', lg: 'px-4 py-3 text-lg' } }, defaultVariants: { intent: 'primary', size: 'sm' } });Usage : button({ intent: 'secondary', size: 'lg' }). Types TypeScript autocomplétés. Combine avec cn() pour merger.
Alternative : tailwind-variants (avec slots, compoundVariants) ou tv().

  • forced-colors: (bonne réponse)
  • high-contrast:
  • a11y-colors:
  • system-colors:
Explication : forced-colors:* applique des styles si l'utilisateur a activé un mode haute lisibilité (Windows High Contrast Mode). Important pour l'accessibilité. Pattern : retirer ombres/dégradés et forcer des bordures explicites en mode forced-colors. contrast-more: et contrast-less: existent aussi pour prefers-contrast.

  • Dupliquer chaque page
  • (1) Utiliser les logical properties (ms/me/ps/pe/start/end), (2) Ajouter dir="rtl" sur &lt;html&gt; selon la langue, (3) Utiliser le préfixe rtl: pour des cas spécifiques (icônes flèches qui doivent flip) (bonne réponse)
  • Utiliser uniquement du JS
  • Impossible avec Tailwind
Explication : Pipeline RTL avec Tailwind : (1) remplacer pl/pr par ps/pe, ml/mr par ms/me, text-left/right par text-start/end ; (2) définir dir="rtl" côté serveur selon la locale ; (3) pour les exceptions (chevrons, icônes), utiliser rtl:rotate-180. Le mécanisme inversion automatique fonctionne sans JS supplémentaire.
Tester dès le début avec dir="rtl" sur la home — beaucoup de bugs RTL viennent d'icônes oubliées.

  • writing-vertical-rl
  • vertical-rl
  • Aucune utility native — utiliser [writing-mode:vertical-rl] en arbitrary (bonne réponse)
  • rotate-90
Explication : writing-mode n'a pas d'utility par défaut (peu commun). Solutions : (1) syntaxe arbitraire [writing-mode:vertical-rl], (2) plugin custom avec addUtilities. Cas d'usage : header asiatique, design éditorial vertical. À ne pas confondre avec rotate-90 (rotation visuelle, pas vraie écriture verticale).

  • Pour réduire la taille du CSS
  • OKLCH est un espace perceptuellement uniforme : les écarts de luminosité entre intensités (50, 100, ..., 900) sont visuellement réguliers, et les interpolations entre couleurs produisent des dégradés sans zones grisâtres (bonne réponse)
  • Pour la compatibilité IE11
  • C'est obligatoire en CSS4
Explication : OKLCH (Oklab + LCH) est l'espace de couleurs perceptuel le plus précis disponible en CSS. Avantages concrets : (1) red-500 et blue-500 ont la même luminosité perçue ; (2) color-mix(in oklch, red, blue) produit des violets vifs (vs grisâtres en sRGB) ; (3) Les nouvelles couleurs P3 et Display HDR sont natives. Tailwind v4 expose --color-blue-500: oklch(...).
Outil utile : oklch.com pour visualiser et générer des palettes.

  • clip-circle
  • [clip-path:circle(50%)] (bonne réponse)
  • shape-circle
  • mask-circle
Explication : clip-path n'a pas d'utility natif (formes trop variées). Solution : syntaxe arbitraire [clip-path:circle(50%)], ou définir un set dans theme.extend.clipPath + plugin avec matchUtilities.

  • Impossible, les keyframes sont externes à Tailwind
  • Utiliser plugin(({ addUtilities }) => { addUtilities({ '@keyframes shake': { ... }, '.animate-shake': { animation: 'shake 0.5s' } }) }) (bonne réponse)
  • Modifier le core
  • Utiliser un CDN externe
Explication : L'API plugin accepte les @keyframes via addUtilities ou addBase. Bonne pratique : encapsuler keyframe + utility dans le même plugin pour la portabilité. Alternative : ajouter dans theme.extend.keyframes + theme.extend.animation, plus déclaratif.
Pour des animations complexes (timelines, scroll-driven), un plugin custom est souvent plus lisible que theme.extend.

  • aria-expanded:
  • aria-[expanded=true]: (bonne réponse)
  • data-aria-expanded:
  • has-aria-expanded:
Explication : aria-[expanded=true]:rotate-180 compile en [aria-expanded="true"] { transform: rotate(180deg); }. Tailwind expose aussi des shorthands : aria-expanded:, aria-checked:, aria-disabled:... pour les attributs ARIA courants. Indispensable pour styler les composants accessibles (accordéons, dropdowns).

  • Impossible avec Tailwind
  • Utiliser des CSS variables comme tokens dans la config (colors: { primary: 'var(--color-primary)' }), puis modifier les variables via JavaScript ou data-attributes (bonne réponse)
  • Charger plusieurs feuilles CSS
  • Recompiler à chaque switch
Explication : // CSS :root { --color-primary: 220 90% 50%; } [data-theme="dark"] { --color-primary: 220 90% 70%; } [data-theme="sunset"] { --color-primary: 20 90% 50%; } // tailwind.config.js colors: { primary: 'hsl(var(--color-primary) / <alpha-value>)' } // JS document.documentElement.dataset.theme = 'sunset';Permet thèmes infinis, switch instantané, sans rebuild. Pattern Vercel, Linear, Notion.
Astuce <alpha-value> : la syntaxe hsl(var(--color-primary) / <alpha-value>) permet à Tailwind d'injecter l'alpha (bg-primary/50).

  • Lister les classes interdites
  • Forcer la génération de classes même si elles ne sont pas détectées dans le scan content (utile pour classes construites dynamiquement) (bonne réponse)
  • Améliorer les performances
  • Activer le dark mode
Explication : safelist: ['bg-red-500', { pattern: /bg-(red|green|blue)-(500|700)/ }]. Utile quand : (1) tu construis des classes en string ('bg-' + color), (2) tu rends du contenu Markdown dynamique, (3) classes injectées par une lib tierce. Attention : les regex permissifs explosent le CSS — toujours scoper variants: [...] aussi pour limiter.
Toujours préférer une approche statique (mapper les classes possibles) à la safelist, sauf cas vraiment dynamique.

  • Aucune, @apply est parfait
  • (1) Recrée le problème CSS classique (croissance, conflits, spécificité), (2) Casse l'aspect inspectable côté DevTools (les classes Tailwind disparaissent), (3) Ralentit le build, (4) Rend l'extraction de design tokens plus difficile (bonne réponse)
  • Bug de Tailwind
  • Compatible uniquement avec React
Explication : @apply est OK pour quelques composants très répétés (.btn, .card). À l'échelle (50+ composants), recréer du CSS sémantique annule l'intérêt utility-first. Préférer : composants framework (React/Vue) + cva, ou utility classes nues directement dans le HTML. La doc Tailwind elle-même conseille de l'éviter par défaut.
Test simple : si tu te retrouves à écrire .btn-primary { @apply btn bg-blue-500; } et .btn-primary-large { @apply btn-primary px-6; } → tu as recréé une cascade CSS qui aurait dû rester en HTML.

  • scroll-mt-16 (bonne réponse)
  • scroll-margin-top-16
  • scrollmargin-top-16
  • scroll-top-16
Explication : scroll-mt-{n} = scroll-margin-top. Utile pour les ancres internes : si tu as un header sticky de 64px, ajoute scroll-mt-16 sur les sections cibles pour qu'elles ne se cachent pas sous le header au scroll. Aussi : scroll-mb-*, scroll-mx-*, scroll-pt-*, scroll-pb-*...

  • Tailwind fonctionne automatiquement à l'intérieur du Shadow DOM
  • Les classes ne traversent pas le Shadow DOM. Solutions : (1) injecter le CSS Tailwind compilé dans le shadow root via adoptedStyleSheets, (2) utiliser ::part() pour exposer des hooks de styling, (3) éviter le Shadow DOM si Tailwind est central (bonne réponse)
  • Tailwind est incompatible avec Web Components
  • Il faut écrire du CSS-in-JS
Explication : Le Shadow DOM isole le CSS : les classes .bg-blue-500 du document ne s'appliquent pas dans le shadow root. Pattern moderne : const sheet = new CSSStyleSheet(); sheet.replaceSync(tailwindCompiledCSS); shadowRoot.adoptedStyleSheets = [sheet];Ou utiliser ::part() pour exposer des éléments stylables depuis le parent.
Lit, Stencil, FAST proposent des intégrations Tailwind documentées avec ce pattern.

  • md:
  • @md: (avec @container sur le parent) (bonne réponse)
  • cq-md:
  • parent-md:
Explication : Container queries Tailwind v3.2+ : <div class="@container"> <div class="@md:flex @lg:grid-cols-3">...</div> </div>Les breakpoints @sm, @md, @lg, @xl, @2xl sont définissables dans la config. Le composant s'adapte à la largeur de son slot, pas de la fenêtre — révolutionnaire pour des layouts vraiment composables.

  • Vérifier manuellement à chaque release
  • Configurer size-limit ou bundlewatch dans la CI : ils alertent si le CSS dépasse un seuil (ex: 30 Ko gzipped) sur chaque PR (bonne réponse)
  • Désactiver les checks
  • Utiliser uniquement DevTools
Explication : Pattern CI : ajouter size-limit dans package.json avec un seuil sur le CSS final. La PR échoue si le bundle gonfle anormalement. Empêche les régressions silencieuses (ajout d'un plugin, safelist trop permissive). Compatible GitHub Actions, GitLab CI, Vercel checks.
Combine avec tailwind-config-viewer en local pour explorer les classes générées.

  • bg-conic from-blue-500 to-red-500
  • bg-conic-gradient
  • Pas d'utility natif jusqu'à v3 — utiliser [background:conic-gradient(...)]. Tailwind v4 introduit bg-conic-* (bonne réponse)
  • conic-gradient-bg
Explication : Tailwind v3 ne fournit que les linear gradients (bg-gradient-to-{dir}). Pour conic-gradient et radial-gradient : syntaxe arbitraire ou plugin. Tailwind v4 ajoute bg-linear-{dir}, bg-radial, bg-conic nativement avec position et stops déclarables.

  • Acceptable, c'est la vie
  • Injecter un script blocking dans &lt;head&gt; qui ajoute la classe dark sur &lt;html&gt; avant le rendu, en lisant localStorage ou prefers-color-scheme (bonne réponse)
  • Utiliser uniquement le mode media
  • Charger Tailwind plus tard
Explication : Pattern obligatoire pour SSR/SSG : <head> <script> (function() { var stored = localStorage.getItem('theme'); if (stored === 'dark' || (!stored && matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark'); } })(); </script> </head>Doit être inline et synchrone, exécuté avant le premier paint. Sinon : flash blanc puis transition vers sombre = expérience cassée.
Next.js avec next-themes automatise ce pattern. Astro et Remix proposent des helpers similaires.

  • @theme inline ou @import "./tokens.css" theme (bonne réponse)
  • theme.import
  • importTheme
  • @includeTheme
Explication : Tailwind v4 introduit @theme en CSS (config CSS-first) : @theme { --color-brand-500: oklch(0.7 0.2 200); --font-display: "Inter Variable"; --spacing-tight: 0.5rem; }Variables CSS auto-traduites en utilities (bg-brand-500, font-display, p-tight). Plus besoin de tailwind.config.js, ou tu peux le coupler.

  • Aucun, c'est un drop-in
  • (1) Renommage bg-gradient-to-r → bg-linear-to-r, (2) suppression de variants dans config (auto en v4), (3) theme.extend en CSS via @theme, (4) couleurs OKLCH peuvent légèrement différer, (5) PostCSS plugin remplacé par Vite/Lightning CSS (bonne réponse)
  • Tout casse
  • v4 n'existe pas encore
Explication : Migration officielle documentée : npx @tailwindcss/upgrade automatise une partie. Points d'attention : nommage gradients, suppression de variants explicites (tout est dispo par défaut), config CSS-first (mais @config permet de garder l'ancienne), nouveau pipeline build (Vite/PostCSS plugin v4). Test visuel obligatoire car OKLCH change subtilement les teintes.
Pour minimiser le risque : audit visuel avec Chromatic/Percy avant et après migration sur un environnement staging.

  • contain-layout-style
  • Pas d'utility natif — syntaxe arbitraire [contain:layout_style] ou plugin (bonne réponse)
  • isolate-layout
  • contains-layout
Explication : contain n'a pas d'utility natif (peu commun). Pour des optimisations perf (forcer un sous-arbre à se rendre indépendamment), utiliser la syntaxe arbitraire ou un plugin custom. À combiner avec content-visibility et contain-intrinsic-size pour des listes très longues.

  • Tailwind est inaccessible par nature
  • Tailwind ne fournit que des styles ; l'accessibilité dépend de la sémantique HTML, des attributs ARIA, du focus management, des labels — qui restent à la charge du développeur (ou via Radix/Headless UI) (bonne réponse)
  • Aucune limite
  • Il faut désactiver Tailwind pour l'a11y
Explication : Tailwind est style-only. Il aide via : sr-only, focus-visible:, motion-reduce:, contrast-more:, forced-colors:, échelle d'intensités calibrée pour le contraste (mais pas une garantie WCAG AA — à vérifier). Pour la vraie a11y comportementale (focus trap, aria-live, keyboard nav) : combiner avec Radix UI, React Aria, Headless UI. Tailwind seul ne fait pas un bouton accessible.
Combo recommandé pour app a11y-critique : Radix UI (logique) + Tailwind (style) + axe-core (audit) + Storybook + screen reader tests manuels.

  • invalid:
  • user-invalid: (bonne réponse)
  • error:
  • required:
Explication : user-invalid:* applique le style uniquement si l'utilisateur a interagi avec l'input et qu'il est invalide. Évite de marquer en rouge un input vide à l'arrivée sur la page. invalid:* existe aussi mais s'applique dès le rendu si vide+required. user-valid:* est le pendant.

  • Aucun outil n'existe
  • ESLint plugin eslint-plugin-tailwindcss + tailwind-merge en CI : détecte classes inconnues, ordres incohérents, conflits, valeurs arbitraires inutiles (bonne réponse)
  • Vérification manuelle obligatoire
  • Forker Tailwind
Explication : eslint-plugin-tailwindcss détecte : (1) classes inexistantes, (2) ordre non standard, (3) classes dupliquées/conflictuelles, (4) usage abusif de valeurs arbitraires (p-[13px]) hors du design system. Configurer en CI avec règle no-arbitrary-value = zéro tolérance pour les hacks pixel.
Combo : eslint-plugin-tailwindcss + prettier-plugin-tailwindcss (tri auto des classes) = qualité maintenue automatiquement.

  • prettier-plugin-tailwindcss (bonne réponse)
  • tailwindcss-prettier
  • tailwind-format
  • tw-prettier
Explication : prettier-plugin-tailwindcss est le plugin officiel : trie automatiquement les classes Tailwind dans l'ordre canonique (layout → spacing → typography → colors...). Améliore la lisibilité, réduit les diffs Git inutiles. Compatible JSX, Vue, Svelte, Astro, Twig, ERB, Liquid via configuration.

  • Impossible avec Angular
  • (1) ng add @ngneat/tailwind ou installer manuellement Tailwind + PostCSS, (2) configurer content: ['./src/**/*.{html,ts}'], (3) importer @tailwind dans styles.css global, (4) utiliser HostBinding ou [class] pour classes dynamiques (bonne réponse)
  • Forker Angular
  • Utiliser uniquement Bootstrap
Explication : Angular utilise webpack/esbuild + PostCSS — Tailwind s'intègre nativement. Pièges : (1) le scanner Tailwind doit voir les fichiers .ts (templates inline), (2) attention au ViewEncapsulation : None permet aux classes Tailwind de s'appliquer aux templates externes ; en Emulated, les classes du HTML enfant sont préservées si elles existent dans le HTML scanné. (3) Combiner avec Angular CDK pour la logique, Tailwind pour le style.
Pour Angular SSR : same FOUC pattern que React/Next — script blocking en <head> pour le mode sombre.

  • mask-fade
  • mask-gradient-r
  • Tailwind v4 expose mask-* et mask-linear-* ; en v3 on passe par [mask-image:linear-gradient(...)] (bonne réponse)
  • fade-mask
Explication : Tailwind v4 introduit mask-{type}, mask-linear-{dir}, mask-radial, mask-no-repeat... pour des effets de fade, vignettage, formes complexes. v3 : syntaxe arbitraire [mask-image:linear-gradient(to_right,black,transparent)] ou plugin custom.

  • Impossible avec Tailwind
  • Définir des fontSizes custom dans theme.extend.fontSize avec clamp(...), ou utiliser plugin tailwindcss-fluid-type, ou syntaxe arbitraire text-[clamp(1rem,2vw,1.5rem)] (bonne réponse)
  • Utiliser uniquement des breakpoints
  • Charger un CDN externe
Explication : Pattern : theme: { extend: { fontSize: { 'fluid-xl': ['clamp(1.5rem, 2.5vw, 2.5rem)', '1.2'], 'fluid-lg': ['clamp(1.125rem, 1.5vw, 1.5rem)', '1.4'] } } }Usage : text-fluid-xl. La syntaxe [fontSize, lineHeight] est supportée. clamp(min, ideal, max) élimine les breakpoints typo.
Outil utile : utopia.fyi/type pour générer des échelles fluides.

  • backdrop-saturate-150 (bonne réponse)
  • saturate-backdrop-150
  • backdrop-150
  • filter-saturate-150
Explication : backdrop-saturate-{n} applique backdrop-filter: saturate(...). Échelle : 0, 50, 100, 150, 200. Combinable avec backdrop-blur, backdrop-brightness, backdrop-contrast... pour des effets glassmorphism complets.

  • Tailwind est obsolète
  • Panda CSS = atomic CSS-in-JS (TypeScript, CVA-style natif, recipes). UnoCSS = engine custom plus rapide et plus flexible (presets, on-demand, attributify). Tailwind reste le plus mature, plus de plugins, plus grosse communauté. (bonne réponse)
  • Ils sont identiques
  • Panda et UnoCSS ne supportent pas le dark mode
Explication : Panda CSS (Chakra) : atomic CSS-in-JS, types-first, runtime-free, intégré à Vite/Next, idéal pour TypeScript-heavy. UnoCSS (Anthony Fu) : engine ultra-flexible, attributify mode (<div bg="blue-500" p="4">), presets composables, build le plus rapide. Tailwind : écosystème dominant, plugins matures (forms, typography, container queries), community immense, support enterprise. Choix selon contexte d'équipe et écosystème.
En entretien : ne pas dénigrer un outil. Tous trois sont valables. Le bon choix dépend du tooling existant et de l'expertise de l'équipe.

  • group-hover:
  • peer-hover: (bonne réponse)
  • has-[.foo]:
  • sibling:
Explication : peer sur le sibling source, peer-hover:*, peer-checked:*, peer-focus:* sur les frères suivants. Limitation : ne fonctionne que vers l'aval (sibling après dans le DOM). Pour styler un parent, utiliser has-[].

  • Aucune action — toutes les couleurs sont en OKLCH par défaut (bonne réponse)
  • @theme oklch
  • color-system: oklch
  • theme.colorMode = oklch
Explication : En Tailwind v4, toutes les couleurs par défaut sont déjà en OKLCH (--color-blue-500: oklch(...)). Aucune action requise. Tu peux mélanger formats (#hex, rgb(), oklch()) — Tailwind les expose tels quels via les CSS variables.

  • Réécriture complète d'un coup
  • (1) Installer Tailwind avec preflight: false, (2) Activer Tailwind sur un wrapper (.tw) avec important: '.tw', (3) Migrer composant par composant, (4) Une fois 80% migré, basculer le preflight et nettoyer le CSS legacy (bonne réponse)
  • Charger Tailwind via CDN
  • Impossible de migrer
Explication : Stratégie d'introduction progressive : // tailwind.config.js module.exports = { important: '.tw', corePlugins: { preflight: false } } // HTML <div class="tw"> <button class="px-4 py-2 bg-blue-500">Migré</button> </div>Empêche les conflits avec le CSS legacy. Quand la majorité est migrée, simplifier la config.
Astuce : ajouter postcss-prefix-selector pour scoper tout Tailwind à .tw automatiquement.

  • Aucun préfixe natif — utiliser data-[dragover=true]: ou has-[] avec attribut (bonne réponse)
  • drop:
  • dropping:
  • drag-over:
Explication : L'API drag-and-drop n'expose pas de pseudo-class CSS native pour dragover. Solution : gérer un attribut/data dans le JS lors des events dragenter/dragleave, puis cibler avec data-[dragover=true]:bg-blue-100. Pattern utilisé par les uploaders de Vercel, Stripe, Linear.

  • Incompatible
  • Tailwind est purement CSS, fonctionne nativement avec RSC et streaming SSR. Pas de runtime JS. Préférer composer les classes côté serveur, utiliser cn() pour les variants. Éviter les hooks de thème dynamiques côté serveur (utiliser CSS vars + cookies) (bonne réponse)
  • Désactiver Tailwind sur le serveur
  • Tailwind ne marche qu'en Client Components
Explication : Tailwind brille avec RSC : pas de CSS-in-JS runtime, donc pas de coût d'hydratation. Patterns : (1) utility classes nues dans les RSC, (2) cn() pour conditionnels statiques, (3) thème via cookies + CSS variables (le serveur lit le cookie et applique le bon theme dès le HTML), (4) éviter useTheme() hook qui force le client.
Voir next-themes v0.3+ qui supporte App Router et écrit les CSS vars au niveau du <html> en SSR (sans flash).

  • Pas d'utility natif — combiner delay-{n} avec nth-* ou via JS animation orchestration (bonne réponse)
  • stagger-100
  • animation-stagger
  • delay-stagger
Explication : Tailwind n'a pas de stagger natif. Solutions : (1) nth-1:delay-100 nth-2:delay-200 ... pour quelques enfants, (2) Framer Motion / Motion One / GSAP pour des animations orchestrées (variants, stagger), (3) JS pur avec animationDelay = i * 100ms. Pour beaucoup d'éléments, JS reste plus pratique.

  • Bug du compilateur
  • (1) Recrée des problèmes de cascade et de spécificité, (2) Casse l'inspection DevTools, (3) Perd le côté composable des utilities, (4) Un composant framework (.tsx, .vue) fait le même travail avec props typés — bien meilleure réutilisation (bonne réponse)
  • @apply n'existe plus en v4
  • Aucune raison
Explication : Adam Wathan (créateur Tailwind) explique : @apply a été initialement créé comme escape hatch, pas comme pattern principal. Pour des composants vraiment réutilisables, un composant React/Vue/Angular avec props typés (souvent via cva ou tailwind-variants) est strictement supérieur : composabilité, réutilisation, typage, autocomplete. @apply est OK pour de vraies primitives CSS (.prose, .markdown-body) mais pas pour des composants UI.
À retenir : si tu peux écrire un composant, fais-le. @apply reste pour les cas où un composant est impossible (CSS pur, Markdown, contenus injectés en HTML).

  • bg-[color-mix(in_oklch,blue,red_50%)] (bonne réponse)
  • bg-mix-blue-red
  • bg-blend-oklch
  • color-mix-50
Explication : Syntaxe arbitraire avec underscore en lieu d'espace (Tailwind les convertit) : bg-[color-mix(in_oklch,blue,red_50%)]. Utile pour des couleurs dynamiques calculées sans plugin. Les fonctions CSS modernes (color-mix, oklch(), color()) sont utilisables ainsi.

  • Aucun outil n'existe
  • (1) axe-core en CI (axe-playwright, jest-axe), (2) Lighthouse a11y score (≥ 90), (3) Storybook + addon-a11y, (4) tests manuels au lecteur d'écran (NVDA, VoiceOver), (5) vérifier contraste avec extensions Stark/Polypane, (6) focus-visible: sur tous les interactifs (bonne réponse)
  • Lecteur d'écran uniquement
  • Tailwind est forcément accessible
Explication : Pipeline a11y complet pour app Tailwind : (automatique) axe-core en CI/CD bloque les régressions évidentes, Lighthouse en preview, Storybook addon-a11y sur chaque composant ; (manuel) tests lecteur d'écran (au moins NVDA + VoiceOver mobile), navigation clavier complète (Tab, Shift-Tab, Esc), modes haute contraste (forced-colors). Pour les contrastes, axe-core détecte 60% des cas — le reste se vérifie à l'œil + outils.
Tailwind facilite (intensités calibrées, focus-visible:, sr-only, motion-reduce:) mais ne remplace pas une démarche a11y rigoureuse. La sémantique HTML + ARIA reste à 100% sur le développeur.

  • Pas d'utility natif — syntaxe arbitraire [scrollbar-gutter:stable] (bonne réponse)
  • scrollbar-stable
  • gutter-stable
  • scroll-gutter-stable
Explication : scrollbar-gutter n'a pas d'utility par défaut. Syntaxe arbitraire [scrollbar-gutter:stable]. Utile pour empêcher le contenu de sauter quand un scroll apparaît/disparaît (modals, contenus dynamiques). À envisager dans un plugin custom si l'app en utilise beaucoup.

  • Tout sur une ligne
  • (1) Ordre canonique (layout → spacing → sizing → typography → backgrounds → borders → effects → transitions → states → responsive), (2) Group logique avec retours à la ligne dans le JSX/template, (3) Extraire dans cva ou variables si > ~10 classes, (4) prettier-plugin-tailwindcss pour automatiser le tri (bonne réponse)
  • Aucune méthode ne marche
  • Mettre toutes les classes en une variable globale
Explication : Conventions saines à grande échelle : (1) ordre canonique appliqué automatiquement par prettier-plugin-tailwindcss, (2) dès qu'un élément dépasse ~10 classes, extraire dans cva ou un objet de classes nommées, (3) pour des composants vraiment partagés, créer un <Card> avec props typés, (4) documenter dans Storybook les variants disponibles. La lisibilité est un investissement de design system, pas un détail.
À éviter absolument : mélanger ordre des classes selon l'inspiration du moment (un fichier git diff devient illisible). Le tri auto via Prettier supprime ce débat.