Skip to content
第 23 章 前端 ⏱ 13 分钟阅读

第 23 章:Tailwind CSS ​

学习目标 ​

  • 掌握 Tailwind 核心概念(utility-first)
  • 熟练使用常用类名
  • 配置自定义主题与插件
  • 避开 Tailwind 的 4 个常见坑

一、Tailwind 是什么? ​

Utility-first CSS 框架,直接在 JSX 写类名生成样式,不用写 CSS 文件:

tsx
<button className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
  点我
</button>

优势:

  • 不用想类名(.btn-primary)
  • 局部样式,无冲突
  • 构建时 PurgeCSS,产物极小
  • 与组件库(shadcn)无缝

二、Next.js 中已内置 ​

create-next-app 时勾选 Tailwind 即可。配置文件 tailwind.config.ts:

ts
import type { Config } from 'tailwindcss';

export default {
  content: ['./src/**/*.{ts,tsx}'],
  theme: {
    extend: {
      colors: {
        brand: '#5B9DF9',
      },
    },
  },
} satisfies Config;

三、核心类名速查 ​

布局 ​

tsx
<div className="flex items-center justify-between gap-4 p-6">
  <div className="grid grid-cols-3 gap-2">
  • flex / grid / block / hidden
  • items-center / justify-between
  • gap-4 / gap-x-2 / gap-y-4
  • p-4 / px-6 / py-2

尺寸 ​

tsx
<div className="w-full max-w-md h-screen">
  • w-1/2 / w-full / w-[300px](任意值)
  • min-h-screen / h-10(1 = 0.25rem = 4px)

颜色 ​

tsx
<div className="bg-blue-500 text-white hover:bg-blue-600">

色阶:50 100 200 ... 900(bg-blue-500 是主色)

文字 ​

tsx
<p className="text-lg font-bold text-gray-700 leading-relaxed">

圆角边框 ​

tsx
<div className="rounded-lg border border-gray-200 shadow-md">

响应式 ​

tsx
<div className="text-sm md:text-base lg:text-lg">

断点:sm 640 / md 768 / lg 1024 / xl 1280 / 2xl 1536

⚠️ 坑 1:移动优先,无前缀 = 移动端,md: 起才是 ≥768px。

四、状态变体 ​

tsx
<button className="bg-blue-500 hover:bg-blue-600 active:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 disabled:opacity-50">
  • hover: / focus: / active: / disabled:
  • dark: — 暗色模式
  • group-hover: — 父级 hover

五、暗色模式 ​

tsx
<div className="bg-white text-black dark:bg-gray-900 dark:text-white">

配置(tailwind.config.ts):

ts
export default {
  darkMode: 'class',     // 用 class 切换
  // ...
};

六、自定义值(任意属性) ​

tsx
<div className="w-[300px] bg-[#bada55] text-[14px] mt-[var(--header-height)]">

七、条件类名:cn 工具 ​

tsx
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',
  isActive && 'bg-blue-500 text-white',
  isDisabled && 'opacity-50 cursor-not-allowed',
)}>

⚠️ 坑 2:clsx 只做条件合并,有冲突类名不会去重。要去重用 tailwind-merge。

八、复用样式:@apply ​

css
/* globals.css */
@layer components {
  .btn-primary {
    @apply px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600;
  }
}
tsx
<button className="btn-primary">点</button>

⚠️ 坑 3:不要过度用 @apply,它会变成新的"全局类",违背 utility-first 初衷。

九、自定义动画 ​

ts
// tailwind.config.ts
theme: {
  extend: {
    keyframes: {
      'fade-in': {
        '0%': { opacity: '0' },
        '100%': { opacity: '1' },
      },
    },
    animation: {
      'fade-in': 'fade-in 0.3s ease-in-out',
    },
  },
}
tsx
<div className="animate-fade-in">淡入</div>

十、shadcn/ui 配合 Tailwind ​

shadcn 生成的组件就是 Tailwind 类名,直接改:

tsx
// components/ui/button.tsx(部分)
import { cn } from '@/lib/utils';

export const Button = ({ className, ...props }) => (
  <button
    className={cn(
      'inline-flex items-center justify-center rounded-md text-sm font-medium',
      'transition-colors focus-visible:outline-none',
      'bg-primary text-primary-foreground hover:bg-primary/90',
      className,
    )}
    {...props}
  />
);

十一、性能与 purge ​

Tailwind 在构建时扫描 content 配置的文件,没用到的不打进 bundle。

ts
content: [
  './src/**/*.{ts,tsx}',     // 必填,否则类名丢失
],

⚠️ 坑 4:content 路径错了 → 类名无效。动态拼接的类名也要写在文件里(完整字符串扫描)。

十二、本章小结 ​

要点关键
Utility-first类名即样式,不写 CSS
响应式移动优先,md: lg:
状态hover focus dark
任意值w-[300px] bg-[#ccc]
合并clsx + tailwind-merge = cn()
shadcn默认基于 Tailwind
性能构建时 PurgeCSS,产物极小

动手练习 ​

  1. 响应式卡片:不同断点变不同布局
  2. 暗色模式:用 dark: 类 + theme 切换
  3. 封装组件:用 cn() 封装带状态变体的 Button
  4. 找坑:以下代码为什么 md:flex 不生效?
    tsx
    <div className="md:flex hidden">内容</div>

下一章:第 24 章:测试 →

本站基于 VitePress 构建 · 由 StackHub 团队维护