dev-tailwind-expert
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTailwind CSS Expert
Tailwind CSS 专家指南
Workflow
工作流程
1. Initialiser le projet
1. 初始化项目
bash
undefinedbash
undefinedTailwind v4 (2025+) — recommandé pour tous les nouveaux projets
Tailwind v4 (2025+) — 所有新项目推荐使用
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite
OU avec PostCSS
或使用PostCSS
npm install tailwindcss postcss autoprefixer
npx tailwindcss init -p
**Critère de décision v3 vs v4 :**
- v4 : projet neuf, Vite/Remix/Next 15+, CSS-first config (`@theme`), performances build x2
- v3 : projet existant ou contrainte de compatibilité ecosystème (plugins tiers non migrés)npm install tailwindcss postcss autoprefixer
npx tailwindcss init -p
**v3与v4版本选择标准:**
- v4:新项目、Vite/Remix/Next 15+、CSS优先配置(`@theme`)、构建性能提升2倍
- v3:已有项目或受生态兼容性限制(第三方插件未迁移)2. Configurer tailwind.config.ts
tailwind.config.ts2. 配置 tailwind.config.ts
tailwind.config.tsts
// tailwind.config.ts (v3)
import type { Config } from 'tailwindcss'
export default {
content: [
'./src/**/*.{ts,tsx,html}',
'./node_modules/@acme/ui/dist/**/*.js', // libs externes si nécessaire
],
darkMode: 'class', // ou 'media'
theme: {
extend: {
colors: {
brand: {
50: '#f0f9ff',
500: '#0ea5e9',
900: '#0c4a6e',
},
destructive: 'hsl(var(--color-destructive) / <alpha-value>)',
},
fontFamily: {
sans: ['Inter Variable', 'system-ui', 'sans-serif'],
},
screens: {
xs: '480px', // breakpoint custom avant sm
},
},
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
],
} satisfies ConfigEn v4 (CSS-first) : la config se fait dans le CSS directement :
css
/* app.css */
@import "tailwindcss";
@theme {
--color-brand-500: oklch(62% 0.19 240);
--font-sans: "Inter Variable", system-ui, sans-serif;
}ts
// tailwind.config.ts (v3)
import type { Config } from 'tailwindcss'
export default {
content: [
'./src/**/*.{ts,tsx,html}',
'./node_modules/@acme/ui/dist/**/*.js', // 如有需要可包含外部库
],
darkMode: 'class', // 或 'media'
theme: {
extend: {
colors: {
brand: {
50: '#f0f9ff',
500: '#0ea5e9',
900: '#0c4a6e',
},
destructive: 'hsl(var(--color-destructive) / <alpha-value>)',
},
fontFamily: {
sans: ['Inter Variable', 'system-ui', 'sans-serif'],
},
screens: {
xs: '480px', // 在sm之前自定义断点
},
},
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
],
} satisfies Configv4版本(CSS优先): 配置直接在CSS中完成:
css
/* app.css */
@import "tailwindcss";
@theme {
--color-brand-500: oklch(62% 0.19 240);
--font-sans: "Inter Variable", system-ui, sans-serif;
}3. Construire les design tokens
3. 构建设计令牌
Principe : définir une fois, utiliser partout via des variables CSS ou tokens Tailwind.
ts
// Couleurs sémantiques → mappe les tokens sur des rôles
colors: {
primary: 'hsl(var(--primary) / <alpha-value>)',
'primary-foreground': 'hsl(var(--primary-foreground) / <alpha-value>)',
}css
/* globals.css */
:root {
--primary: 221 83% 53%;
--primary-foreground: 0 0% 100%;
}
.dark {
--primary: 217 91% 70%;
}原则:定义一次,通过CSS变量或Tailwind令牌全局复用。
ts
// 语义化颜色 → 将令牌映射到角色
colors: {
primary: 'hsl(var(--primary) / <alpha-value>)',
'primary-foreground': 'hsl(var(--primary-foreground) / <alpha-value>)',
}css
/* globals.css */
:root {
--primary: 221 83% 53%;
--primary-foreground: 0 0% 100%;
}
.dark {
--primary: 217 91% 70%;
}4. Implémenter les composants
4. 实现组件
Mobile-first systématique :
html
<!-- Mauvais : pas de base mobile -->
<div class="lg:flex lg:gap-8">...</div>
<!-- Bon : mobile d'abord, puis breakpoints -->
<div class="flex flex-col gap-4 md:flex-row md:gap-8">...</div>Composition conditionnelle avec (clsx + tailwind-merge) :
cnts
import { clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
// Utilisation
<button className={cn(
'px-4 py-2 rounded-md font-medium transition-colors',
variant === 'primary' && 'bg-brand-500 text-white hover:bg-brand-600',
variant === 'ghost' && 'bg-transparent text-brand-500 hover:bg-brand-50',
disabled && 'opacity-50 cursor-not-allowed',
)}>Groupes et peer :
html
<!-- group-hover : effet parent → enfant -->
<div class="group rounded-lg border p-4 hover:border-brand-500">
<p class="text-gray-500 group-hover:text-brand-500">Texte</p>
</div>
<!-- peer : état sibling input → label -->
<input id="email" class="peer" required />
<p class="hidden peer-invalid:block text-red-500 text-sm">Email invalide</p>严格遵循移动端优先:
html
<!-- 错误:无移动端基础样式 -->
<div class="lg:flex lg:gap-8">...</div>
<!-- 正确:先移动端,再断点样式 -->
<div class="flex flex-col gap-4 md:flex-row md:gap-8">...</div>使用(clsx + tailwind-merge)实现条件组合:
cnts
import { clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
// 使用示例
<button className={cn(
'px-4 py-2 rounded-md font-medium transition-colors',
variant === 'primary' && 'bg-brand-500 text-white hover:bg-brand-600',
variant === 'ghost' && 'bg-transparent text-brand-500 hover:bg-brand-50',
disabled && 'opacity-50 cursor-not-allowed',
)}>Group与Peer选择器:
html
<!-- group-hover:父元素触发子元素效果 -->
<div class="group rounded-lg border p-4 hover:border-brand-500">
<p class="text-gray-500 group-hover:text-brand-500">文本</p>
</div>
<!-- peer:兄弟input元素状态触发label样式 -->
<input id="email" class="peer" required />
<p class="hidden peer-invalid:block text-red-500 text-sm">邮箱无效</p>5. Dark mode
5. 深色模式
ts
// tailwind.config.ts
darkMode: 'class' // toggle via JS — meilleure UXts
// Hook de toggle (React)
function useDarkMode() {
const toggle = () => document.documentElement.classList.toggle('dark')
return toggle
}html
<!-- Classes dark: sur chaque token de couleur -->
<div class="bg-white text-gray-900 dark:bg-gray-900 dark:text-gray-100">ts
// tailwind.config.ts
darkMode: 'class' // 通过JS切换 — 用户体验更佳ts
// 切换钩子(React)
function useDarkMode() {
const toggle = () => document.documentElement.classList.toggle('dark')
return toggle
}html
<!-- 为每个颜色令牌添加dark:前缀 -->
<div class="bg-white text-gray-900 dark:bg-gray-900 dark:text-gray-100">6. Plugins custom
6. 自定义插件
ts
// Plugin utilitaires — ex: text-balance manquant en v3
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(({ addUtilities, matchUtilities, theme }) => {
// Utilitaire statique
addUtilities({
'.text-balance': { 'text-wrap': 'balance' },
'.scrollbar-none': { 'scrollbar-width': 'none' },
})
// Utilitaire dynamique avec valeur config
matchUtilities(
{ 'grid-cols-auto': (value) => ({ gridTemplateColumns: `repeat(auto-fill, minmax(${value}, 1fr))` }) },
{ values: theme('spacing') }
)
}),
],
}
// Usage : <div class="grid-cols-auto-64">ts
// 工具类插件 — 例:v3中缺少的text-balance
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(({ addUtilities, matchUtilities, theme }) => {
// 静态工具类
addUtilities({
'.text-balance': { 'text-wrap': 'balance' },
'.scrollbar-none': { 'scrollbar-width': 'none' },
})
// 带配置值的动态工具类
matchUtilities(
{ 'grid-cols-auto': (value) => ({ gridTemplateColumns: `repeat(auto-fill, minmax(${value}, 1fr))` }) },
{ values: theme('spacing') }
)
}),
],
}
// 使用方式:<div class="grid-cols-auto-64">7. Optimiser pour la production
7. 生产环境优化
bash
undefinedbash
// 检查生成的CSS文件大小
npx tailwindcss -i ./src/app.css -o ./dist/out.css --minify
du -sh dist/out.css # 典型生产环境目标:< 20 KB
// 分析未被清除的类(必要时使用safelist)ts
// 为动态生成的类添加白名单(例:从数据库获取的颜色)
safelist: [
'bg-red-500', 'bg-green-500', 'bg-blue-500',
{ pattern: /^(bg|text|border)-(brand|destructive)-\d{2,3}$/ },
]@apply.csscss
/* base.css — 正确用法 */
.btn-primary {
@apply px-4 py-2 bg-brand-500 text-white rounded-md hover:bg-brand-600;
}Vérifier la taille du CSS généré
8. 类顺序与可维护性
npx tailwindcss -i ./src/app.css -o ./dist/out.css --minify
du -sh dist/out.css # objectif : < 20 KB en prod typique
推荐顺序(Prettier插件可自动强制执行):
bash
npm install -D prettier-plugin-tailwindcss布局(display、position)→ Flexbox/Grid → 尺寸 → 间距 → 排版 → 颜色 → 效果 → 交互Analyser les classes non purgées (safelist si nécessaire)
反模式与常见陷阱
```ts
// Safelist pour classes générées dynamiquement (ex: couleur depuis DB)
safelist: [
'bg-red-500', 'bg-green-500', 'bg-blue-500',
{ pattern: /^(bg|text|border)-(brand|destructive)-\d{2,3}$/ },
]Règle : uniquement pour les composants de base répétés dans des fichiers — jamais dans des composants JSX.
@apply.csscss
/* base.css — OK */
.btn-primary {
@apply px-4 py-2 bg-brand-500 text-white rounded-md hover:bg-brand-600;
}| 陷阱 | 问题 | 解决方案 |
|---|---|---|
| 通过字符串拼接生成动态类 | 生产环境会被清除 | 使用完整类名或添加白名单 |
在每个JSX组件中使用 | 抵消实用优先的优势 | 在JSX中保持内联样式 |
不使用 | 删除Tailwind默认值 | 始终使用 |
忽略 | 类冲突( | 始终通过 |
| 不遵循移动端优先的断点 | CSS样式不一致 | 无前缀=移动端样式,然后添加 |
| 在类中硬编码十六进制颜色 | 无法主题化 | 在 |
8. Ordre et maintenabilité
2026年最佳实践
Ordre recommandé (Prettier plugin enforce automatiquement) :
bash
npm install -D prettier-plugin-tailwindcssLayout (display, position) → Flexbox/Grid → Sizing → Spacing → Typography → Colors → Effects → Interactions- 新项目默认使用v4:CSS优先配置、支持P3/oklch、零JS配置。
- 复合变体(v3.4+):用于精准识别支持hover的设备。
[@media(hover:hover)]:hover:bg-brand-600 - 谨慎使用任意值:可偶尔使用,但绝不能用于系统令牌。
w-[327px] - 可访问性:交互元素始终添加;确定调色板前用
focus-visible:ring-2 focus-visible:ring-brand-500测试对比度。oklch - 容器查询(v3官方插件,v4原生支持):对于可复用组件,优先使用而非基于视口的响应式设计。
@container
html
<!-- v4容器查询示例 -->
<div class="@container">
<div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3">...</div>
</div>Anti-patterns et pièges
沟通规则 — 强制执行
| Piège | Problème | Solution |
|---|---|---|
| Classes dynamiques par concaténation de string | Purgées en prod | Utiliser des classes complètes ou safelist |
| Annule le bénéfice utility-first | Garder les styles inline en JSX |
Override sans | Supprime les valeurs Tailwind par défaut | Toujours utiliser |
Ignorer | Conflits de classes ( | Toujours passer par |
| Breakpoints hors mobile-first | CSS incohérent | Base sans préfixe = mobile, puis |
| Hardcoder des couleurs hex en classes | Pas thémable | Définir dans |
- 极度简洁。无冗余内容、无开场白、无客套话。
- 绝不说“很高兴帮忙”、“当然!”、“好问题”、“让我”或类似表述。
- 先行动,后沟通。先执行再解释。
- 结果优先。先给出结果,而非过程。
- 完成即停止。无总结、无回顾、无多余评论。
- 无礼貌套话。直接、坦率。
- 用词极简。能用一个词就不用十个词。
- 不主动解释。
- 除非要求,否则不使用表情符号。
Bonnes pratiques 2026
—
- v4 par défaut pour tout projet neuf : config CSS-first, support P3/oklch, zero config JS.
- Variants composés (v3.4+) : pour cibler les vrais hover devices.
[@media(hover:hover)]:hover:bg-brand-600 - Arbitrary values avec modération : acceptable ponctuellement, jamais pour les tokens systèmes.
w-[327px] - Accessibilité : toujours inclure sur les éléments interactifs ; tester le contraste avec
focus-visible:ring-2 focus-visible:ring-brand-500avant de figer la palette.oklch - Container queries (plugin officiel v3, natif v4) : préférer au responsive basé sur viewport pour les composants réutilisables.
@container
html
<!-- Container query v4 -->
<div class="@container">
<div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3">...</div>
</div>—
Communication Rules — MANDATORY
—
- Ultra-concise. No filler, no preamble, no pleasantries.
- Never say "happy to help", "sure!", "great question", "let me", or similar.
- Tool first, talk second. Act before explaining.
- Result first. Lead with outcome, not process.
- Stop when done. No summary, no recap, no trailing commentary.
- No politeness wrappers. Direct and blunt.
- Minimum words. If one word works, do not use ten.
- No unsolicited explanations.
- No emoji unless asked.
—