Post

Tailwind CSS 项目实践:团队使用规范

Tailwind CSS 项目实践:团队使用规范

团队规范框架

在没有规范的情况下,团队使用 Tailwind CSS 经常会遇到以下问题:样式不一致、代码重复、维护困难、性能问题。

所以我们的规范主要包含以下几个方面:

  1. 统一的 tailwind.config.js 配置
  2. class 组合和组件命名规范
  3. 样式复用和抽象层级
  4. 文件结构和样式管理
  5. lint 规则和 code review 标准
  6. 打包和 purge(自动移除未使用 CSS 类) 最佳实践

1. 配置标准化

统一的设计 tokens

首先建立团队共用的tailwind.config.js配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// tailwind.config.js
module.exports = {
  content: [
    "./src/**/*.{js,ts,jsx,tsx,vue,html}",
    "./components/**/*.{js,ts,jsx,tsx,vue}",
  ],
  theme: {
    extend: {
      // 品牌色彩系统
      colors: {
        primary: {
          50: "#eff6ff",
          100: "#dbeafe",
          500: "#3b82f6",
          600: "#2563eb",
          700: "#1d4ed8",
          900: "#1e3a8a",
        },
        gray: {
          50: "#f9fafb",
          100: "#f3f4f6",
          200: "#e5e7eb",
          500: "#6b7280",
          700: "#374151",
          900: "#111827",
        },
      },
      // 统一的字体系统
      fontSize: {
        xs: ["12px", { lineHeight: "16px" }],
        sm: ["14px", { lineHeight: "20px" }],
        base: ["16px", { lineHeight: "24px" }],
        lg: ["18px", { lineHeight: "28px" }],
        xl: ["20px", { lineHeight: "28px" }],
        "2xl": ["24px", { lineHeight: "32px" }],
      },
      // 间距系统
      spacing: {
        18: "4.5rem",
        72: "18rem",
        84: "21rem",
        96: "24rem",
      },
      // 屏幕尺寸
      screens: {
        xs: "475px",
        sm: "640px",
        md: "768px",
        lg: "1024px",
        xl: "1280px",
        "2xl": "1536px",
      },
    },
  },
  plugins: [
    require("@tailwindcss/forms"),
    require("@tailwindcss/typography"),
    require("@tailwindcss/aspect-ratio"),
  ],
};

团队配置管理策略

  1. 版本控制:将配置文件纳入 Git 管理,确保团队同步
  2. 配置继承:不同项目可以基于基础配置进行扩展
  3. 定期 review:每月 review 配置文件,删除不用的 tokens

2. 命名约定和组织规范

Class 组合命名规范

建立清晰的 class 组合命名约定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ❌ 不推荐:混乱的class排序
<div className="text-white bg-blue-500 p-4 rounded-lg shadow-md hover:bg-blue-600 flex items-center">

// ✅ 推荐:按功能模块分组
<div className="
  // Layout
  flex items-center
  // Spacing
  p-4
  // Background & Border
  bg-blue-500 rounded-lg
  // Typography
  text-white
  // Effects
  shadow-md
  // Interactions
  hover:bg-blue-600
">

可以使用 Prettier 的 Tailwind CSS 插件。

组件级别的样式抽象

对于重复使用的样式组合,我们采用三层抽象策略:

第一层:原子类直接使用

1
2
// 简单、一次性的样式
<span className="text-sm text-gray-500">辅助文本</span>

第二层:样式组合抽象

1
2
3
4
5
6
7
8
9
10
11
12
// utils/styles.js
export const buttonStyles = {
  base: "px-4 py-2 font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2",
  primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500",
  secondary: "bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-500",
  danger: "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500",
}

// 使用方式
<button className={`${buttonStyles.base} ${buttonStyles.primary}`}>
  主要按钮
</button>

第三层:组件封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// components/Button.jsx
import { buttonStyles } from "../utils/styles";

export const Button = ({
  variant = "primary",
  size = "md",
  children,
  ...props
}) => {
  const sizeClasses = {
    sm: "px-3 py-1.5 text-sm",
    md: "px-4 py-2",
    lg: "px-6 py-3 text-lg",
  };

  return (
    <button
      className={`
        ${buttonStyles.base} 
        ${buttonStyles[variant]} 
        ${sizeClasses[size]}
      `}
      {...props}
    >
      {children}
    </button>
  );
};

3. 代码组织和文件结构

推荐的项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
src/
├── styles/
│   ├── globals.css          # 全局样式和Tailwind导入
│   ├── components.css       # 组件级别的@apply样式
│   └── utilities.css        # 自定义工具类
├── utils/
│   ├── styles.js           # 样式组合工具
│   └── cn.js               # className合并工具
├── components/
│   ├── ui/                 # 基础UI组件
│   │   ├── Button.jsx
│   │   ├── Input.jsx
│   │   └── Modal.jsx
│   └── business/           # 业务组件
└── pages/                  # 页面组件

样式管理最佳实践

1. 全局样式管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* 全局基础样式 */
@layer base {
  html {
    @apply scroll-smooth;
  }

  body {
    @apply bg-gray-50 text-gray-900 antialiased;
  }
}

/* 组件样式 */
@layer components {
  .btn-primary {
    @apply px-4 py-2 bg-blue-600 text-white rounded-md font-medium;
    @apply hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500;
    @apply transition-colors duration-200;
  }
}

2. className 合并工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// utils/cn.js
import { clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs) {
  return twMerge(clsx(inputs))
}

// 使用示例
<div className={cn(
  "base-styles",
  isActive && "active-styles",
  className // 允许外部覆盖
)}>

4. 质量保证

ESLint 和 Prettier 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// .eslintrc.js
module.exports = {
  extends: [
    // ... 其他配置
  ],
  plugins: ["tailwindcss"],
  rules: {
    // Tailwind特定规则
    "tailwindcss/classnames-order": "warn",
    "tailwindcss/no-custom-classname": "warn",
    "tailwindcss/no-contradicting-classname": "error",
  },
  settings: {
    tailwindcss: {
      config: "tailwind.config.js",
    },
  },
};

代码审查检查清单

我们制定了专门的 Tailwind CSS 代码审查清单:

设计一致性

  • 是否使用了统一的颜色 token
  • 字体大小和行高是否符合设计系统
  • 间距是否使用标准的 spacing scale

代码质量

  • class 名是否按照约定顺序排列
  • 是否有不必要的样式重复
  • 复杂的样式组合是否应该抽象为组件

性能考虑

  • 是否使用了不必要的复杂选择器
  • 响应式设计是否合理
  • 是否有 unused 的样式类

自动化工具集成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// package.json
{
  "scripts": {
    "lint:css": "stylelint '**/*.{css,scss}' --fix",
    "lint:tw": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
    "build:css": "tailwindcss -i ./src/styles/globals.css -o ./dist/output.css --watch"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
    "*.{css,scss}": ["stylelint --fix"]
  }
}

5. 性能优化实践

Purge 配置优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// tailwind.config.js
module.exports = {
  content: [
    // 精确指定文件路径,避免扫描不必要的文件
    "./src/pages/**/*.{js,ts,jsx,tsx}",
    "./src/components/**/*.{js,ts,jsx,tsx}",
    "./src/utils/**/*.{js,ts}",
    // 如果使用动态class名,添加白名单
    "./src/styles/safelist.txt",
  ],
  // 生产环境配置
  ...(process.env.NODE_ENV === "production" && {
    purge: {
      options: {
        safelist: [
          // 动态生成的class名
          /^bg-/,
          /^text-/,
          // 第三方库的class名
          "swiper-slide",
          "swiper-pagination",
        ],
      },
    },
  }),
};

打包分析和监控

1
2
3
4
5
6
7
8
9
10
11
12
// 添加bundle分析
const BundleAnalyzerPlugin =
  require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: "static",
      openAnalyzer: false,
    }),
  ],
};

常见问题和解决方案

Q1: 长串 class 名影响可读性怎么办?

解决方案

1
2
3
4
5
6
7
8
9
10
11
// 使用模板字符串分行
const cardClasses = `
  bg-white rounded-lg shadow-md
  p-6 space-y-4
  hover:shadow-lg transition-shadow
  border border-gray-200
`

<div className={cardClasses}>
  {/* 内容 */}
</div>

Q2: 动态样式如何处理?

解决方案

1
2
3
4
5
6
7
8
// 使用条件渲染和样式映射
const statusStyles = {
  success: 'bg-green-100 text-green-800 border-green-200',
  warning: 'bg-yellow-100 text-yellow-800 border-yellow-200',
  error: 'bg-red-100 text-red-800 border-red-200'
}

<div className={`base-styles ${statusStyles[status]}`}>

Q3: 如何处理复杂的响应式设计?

解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
// 使用组件封装复杂响应式逻辑
const ResponsiveGrid = ({ children }) => (
  <div
    className="
    grid grid-cols-1 gap-4
    sm:grid-cols-2 sm:gap-6
    lg:grid-cols-3 lg:gap-8
    xl:grid-cols-4
  "
  >
    {children}
  </div>
);

总结与展望

通过建立完善的 Tailwind CSS 团队规范,大幅提升开发效率和代码质量,更重要的是建立了团队协作的共同语言。这套规范可以根据项目需求和技术发展持续优化。

This post is licensed under CC BY 4.0 by the author.