Tailwind CSS 实用优先思想 #

什么是实用优先 #

实用优先(Utility-First)是一种 CSS 架构方法,它主张使用小型的、单一用途的类来构建界面,而不是为每个组件编写自定义 CSS。

传统方式 vs 实用优先 #

html
<!-- 传统方式:语义化类名 + 自定义 CSS -->
<style>
  .card {
    background-color: white;
    border-radius: 0.5rem;
    padding: 1.5rem;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
  }
  .card-title {
    font-size: 1.25rem;
    font-weight: 600;
    color: #111827;
    margin-bottom: 0.5rem;
  }
  .card-description {
    color: #6b7280;
    line-height: 1.5;
  }
  .card-button {
    margin-top: 1rem;
    background-color: #3b82f6;
    color: white;
    padding: 0.5rem 1rem;
    border-radius: 0.375rem;
    transition: background-color 0.2s;
  }
  .card-button:hover {
    background-color: #2563eb;
  }
</style>

<div class="card">
  <h3 class="card-title">标题</h3>
  <p class="card-description">描述内容</p>
  <button class="card-button">操作</button>
</div>
html
<!-- 实用优先:直接使用实用类 -->
<div class="bg-white rounded-lg p-6 shadow-md">
  <h3 class="text-xl font-semibold text-gray-900 mb-2">标题</h3>
  <p class="text-gray-500 leading-relaxed">描述内容</p>
  <button class="mt-4 bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 transition-colors">
    操作
  </button>
</div>

实用优先的优势 #

1. 无需命名 #

传统 CSS 开发中最头疼的问题之一就是命名:

css
/* 到底用哪个名字? */
.card { }
.card-wrapper { }
.card-container { }
.card-box { }
.card-component { }

实用优先完全避免了这个问题:

html
<!-- 直接描述样式,无需命名 -->
<div class="bg-white rounded-lg p-6">
  ...
</div>

2. 无需切换文件 #

html
<!-- 传统方式:需要在 HTML 和 CSS 之间切换 -->
<!-- HTML -->
<div class="card">...</div>

/* CSS */
.card { ... }
html
<!-- 实用优先:所有样式都在 HTML 中 -->
<div class="bg-white rounded-lg p-6">...</div>

3. 样式局部化 #

html
<!-- 传统方式:CSS 是全局的,可能产生冲突 -->
<style>
  .btn { padding: 10px; }  /* 全局样式 */
  .header .btn { padding: 5px; }  /* 需要覆盖 */
</style>
html
<!-- 实用优先:样式直接在元素上,不会冲突 -->
<button class="px-4 py-2">普通按钮</button>
<button class="px-2 py-1">小按钮</button>

4. 更容易维护 #

html
<!-- 传统方式:需要查找 CSS 文件 -->
<div class="card">  <!-- 样式在哪? -->
  ...
</div>
html
<!-- 实用优先:样式一目了然 -->
<div class="bg-white rounded-lg p-6 shadow-md">  <!-- 样式清晰可见 -->
  ...
</div>

5. 更小的 CSS 文件 #

css
/* 传统方式:大量重复的 CSS */
.card-1 { background: white; padding: 1rem; border-radius: 0.5rem; }
.card-2 { background: white; padding: 1rem; border-radius: 0.5rem; }
.card-3 { background: white; padding: 1rem; border-radius: 0.5rem; }
/* ...更多重复 */
html
<!-- 实用优先:复用相同的类 -->
<div class="bg-white p-4 rounded-lg">卡片 1</div>
<div class="bg-white p-4 rounded-lg">卡片 2</div>
<div class="bg-white p-4 rounded-lg">卡片 3</div>

常见误解 #

误解 1:内联样式一样? #

html
<!-- 内联样式:无法使用响应式、状态等 -->
<div style="background: blue; padding: 16px;">
  内容
</div>

<!-- Tailwind CSS:支持响应式、状态等 -->
<div class="bg-blue-500 p-4 hover:bg-blue-600 md:p-6">
  内容
</div>

误解 2:HTML 会变得臃肿? #

html
<!-- 实际上,语义化类名也需要写很多 CSS -->
<div class="card card--featured card--large">
  ...
</div>

<style>
.card { /* 很多 CSS */ }
.card--featured { /* 很多 CSS */ }
.card--large { /* 很多 CSS */ }
</style>

误解 3:无法复用? #

html
<!-- 使用组件抽象复用 -->
<!-- Button.vue -->
<template>
  <button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
    <slot />
  </button>
</template>

<!-- 使用 -->
<Button>点击我</Button>

何时提取组件 #

规则:重复三次以上 #

html
<!-- 第一次出现 -->
<button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
  按钮
</button>

<!-- 第二次出现 -->
<button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
  按钮
</button>

<!-- 第三次出现:考虑提取组件 -->
<Button>按钮</Button>

使用 @apply 提取 #

css
/* 不推荐:回到传统 CSS 的老路 */
.btn {
  @apply px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600;
}
html
<!-- 推荐:使用组件 -->
<!-- Button.vue -->
<template>
  <button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
    <slot />
  </button>
</template>

组件化示例 #

jsx
// React 组件
function Button({ children, variant = 'primary' }) {
  const variants = {
    primary: 'bg-blue-500 hover:bg-blue-600 text-white',
    secondary: 'bg-gray-200 hover:bg-gray-300 text-gray-800',
    danger: 'bg-red-500 hover:bg-red-600 text-white',
  }
  
  return (
    <button className={`px-4 py-2 rounded ${variants[variant]}`}>
      {children}
    </button>
  )
}

// 使用
<Button>主要按钮</Button>
<Button variant="secondary">次要按钮</Button>
<Button variant="danger">危险按钮</Button>
vue
<!-- Vue 组件 -->
<template>
  <button :class="buttonClasses">
    <slot />
  </button>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  variant: {
    type: String,
    default: 'primary'
  }
})

const variants = {
  primary: 'bg-blue-500 hover:bg-blue-600 text-white',
  secondary: 'bg-gray-200 hover:bg-gray-300 text-gray-800',
  danger: 'bg-red-500 hover:bg-red-600 text-white',
}

const buttonClasses = computed(() => 
  `px-4 py-2 rounded ${variants[props.variant]}`
)
</script>

设计约束 #

Tailwind CSS 通过设计约束帮助你保持一致性。

间距约束 #

html
<!-- 推荐:使用预定义值 -->
<div class="p-4">  <!-- 16px -->
<div class="p-6">  <!-- 24px -->
<div class="p-8">  <!-- 32px -->

<!-- 避免:随意值 -->
<div class="p-[15px]">  <!-- 打破设计系统 -->

颜色约束 #

html
<!-- 推荐:使用预定义颜色 -->
<div class="bg-blue-500">
<div class="bg-blue-600">
<div class="bg-blue-700">

<!-- 避免:随意颜色 -->
<div class="bg-[#4a90d9]">  <!-- 打破设计系统 -->

字体约束 #

html
<!-- 推荐:使用预定义字体大小 -->
<p class="text-sm">   <!-- 14px -->
<p class="text-base"> <!-- 16px -->
<p class="text-lg">   <!-- 18px -->

<!-- 避免:随意字体大小 -->
<p class="text-[15px]">  <!-- 打破设计系统 -->

实用优先的工作流程 #

1. 从布局开始 #

html
<div class="min-h-screen flex items-center justify-center">
  <!-- 页面内容 -->
</div>

2. 添加容器 #

html
<div class="min-h-screen flex items-center justify-center">
  <div class="w-full max-w-md">
    <!-- 卡片内容 -->
  </div>
</div>

3. 构建组件 #

html
<div class="min-h-screen flex items-center justify-center bg-gray-100">
  <div class="w-full max-w-md bg-white rounded-lg shadow-lg p-8">
    <h2 class="text-2xl font-bold text-gray-900 mb-6">登录</h2>
    <!-- 表单内容 -->
  </div>
</div>

4. 添加交互 #

html
<div class="min-h-screen flex items-center justify-center bg-gray-100">
  <div class="w-full max-w-md bg-white rounded-lg shadow-lg p-8">
    <h2 class="text-2xl font-bold text-gray-900 mb-6">登录</h2>
    <form class="space-y-4">
      <input class="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="邮箱">
      <input class="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="密码">
      <button class="w-full bg-blue-500 text-white py-2 rounded-lg hover:bg-blue-600 transition-colors">
        登录
      </button>
    </form>
  </div>
</div>

最佳实践 #

1. 保持类名有序 #

html
<!-- 推荐顺序:布局 → 尺寸 → 间距 → 视觉 → 状态 -->
<div class="
  flex items-center justify-center
  w-full h-12
  px-4 py-2
  bg-blue-500 text-white rounded-lg
  hover:bg-blue-600
">
  按钮
</div>

2. 使用组件抽象 #

jsx
// 不要重复相同的类名
function Card({ children }) {
  return (
    <div className="bg-white rounded-lg shadow-md p-6">
      {children}
    </div>
  )
}

3. 合理使用任意值 #

html
<!-- 必要时使用任意值 -->
<div class="w-[calc(100%-2rem)]">
  特殊计算宽度
</div>

4. 利用编辑器插件 #

安装 Tailwind CSS IntelliSense 插件,获得:

  • 类名自动补全
  • 悬停预览 CSS
  • 语法高亮
  • 错误提示

下一步 #

理解实用优先思想后,开始学习 布局 掌握具体的实用类使用!

最后更新:2026-03-28