Tailwind:流行的原子化 CSS 框架

318 阅读5分钟

Tailwind 是流行的原子化 css 框,star 很多,npm下载量也很大。

1 什么是原子化 CSS?

传统的 CSS 写法是定义一个类,然后在类内部写样式,例如:

<div class="text"></div>
.text {
    font-size: 16px;
    border: 1px solid #000;
    padding: 4px;
}

而原子化 CSS 则是将样式细分为多个小的类,每个类只包含一个样式属性,例如:

<div class="text-base p-1 border border-black border-solid"></div>
.text-base {
    font-size: 16px;
}
.p-1 {
    padding: 4px;
}
.border {
    border-width: 1px;
}
.border-black {
    border-color: black;
}
.border-solid {
    border-style: solid;
}

2 Tailwind 的优势

  1. 减少命名困扰:不需要为每个样式起名字,直接使用预定义的类名。
  2. 避免样式重复:相同的样式只需定义一次,避免了重复代码。
  3. 局部作用域:样式只作用于特定的 HTML 标签,避免全局污染。

3 使用 Tailwind

  1. 创建项目:
pnpm create vite tailwind-test --template react-ts
cd tailwind-test
pnpm i
pnpm i tailwindcss -D
npx tailwindcss init
  1. 配置 Tailwind:在 src/index.css 中引入 Tailwind 的基础样式、组件样式和工具样式:
@tailwind base;
@tailwind components;
@tailwind utilities;

这些层级按照上述顺序被应用,这意味着 utilities 中的样式会覆盖 components 中的样式,而 components 中的样式会覆盖 base 中的样式。

  1. tailwind.config.js:
/** @type {import('tailwindcss').Config} */
export default {
  // 指定需要处理的文件
  content: ['./src/**/*.{js,ts,jsx,tsx}', './index.html'],
  // 主题配置
  theme: {
    // 扩展默认主题
    extend: {}
  },
  // 插件配置
  plugins: []
}

  1. vite 引入:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from 'tailwindcss'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  css: {
    postcss: {
      plugins: [tailwindcss]
    }
  }
})
  1. 使用 Tailwind 类:
function App() {
  return (
    <div className="container mx-auto p-8 bg-gray-50">
      <h1 className="text-4xl font-bold mb-8 text-indigo-700 text-center">Tailwind CSS 示例</h1>

      {/* 文本样式 */}
      <Section title="文本样式">
        <p className="text-lg text-gray-700 mb-2 leading-relaxed">这是普通文本</p>
        <p className="text-xl font-bold text-emerald-600 mb-2">这是粗体绿色文本</p>
        <p className="text-sm italic text-purple-600">这是小号斜体紫色文本</p>
      </Section>

      {/* 背景和边框 */}
      <Section title="背景和边框">
        <div className="bg-amber-100 p-6 rounded-lg shadow-lg border border-amber-200">
          黄色背景,圆角,阴影
        </div>
        <div className="mt-4 border-2 border-teal-400 p-6 rounded-md">青色边框</div>
      </Section>

      {/* 弹性布局 */}
      <Section title="弹性布局">
        <div className="flex justify-between items-center bg-gray-100 p-6 rounded-lg">
          {Object.entries(bgColors).map(([color, bgClass], index) => (
            <div key={color} className={`${bgClass} text-white p-3 rounded-md shadow-md`}>
              项目 {index + 1}
            </div>
          ))}
        </div>
      </Section>

      {/* 响应式设计 */}
      <Section title="响应式设计">
        <div className="bg-pink-200 p-6 sm:bg-purple-200 md:bg-indigo-200 lg:bg-blue-200 rounded-lg transition-colors duration-300">
          这个div在不同屏幕尺寸下会改变背景颜色
        </div>
      </Section>

      {/* 悬停和状态 */}
      <Section title="悬停和状态">
        <button className="bg-indigo-500 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded-full transition duration-300 shadow-md hover:shadow-lg">
          悬停我
        </button>
        <input
          type="text"
          className="mt-4 w-full border-2 border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 rounded-lg p-3 transition duration-300"
          placeholder="点击我聚焦"
        />
      </Section>
    </div>
  )
}

// 定义颜色映射对象
const bgColors: Record<string, string> = {
  blue: 'bg-blue-500',
  green: 'bg-green-500',
  red: 'bg-red-500'
}

// 提取可重用的 Section 组件
function Section({ title, children }) {
  return (
    <section className="mb-12 bg-white p-6 rounded-xl shadow-md">
      <h2 className="text-2xl font-semibold mb-6 text-indigo-600 border-b-2 border-indigo-200 pb-2">
        {title}
      </h2>
      {children}
    </section>
  )
}

export default App

  1. 运行项目:
pnpm dev

4 配置与扩展

  • 修改预定义类:在 tailwind.config.js 中修改配置,例如:
theme: {
  extend: {
    padding: {
      '1': '30px',
    },
  },
}

使用 p-1 来应用 30px 的内边距。例如:

<div class="p-1">  
  This div has a padding of 30px on all sides.  
</div>

这样设置后,p-1 将不再是默认的 0.25rem(通常是 4px),而是 30px

  • 临时设置值:使用 [] 语法,例如 text-[14px] 生成 font-size: 14px 的样式。
  • 响应式与状态样式:例如 hover:text-[30px]md:bg-blue-500
  • 扩展类:使用 @layer(指定层级自定义样式) 和 @apply(直接自定义样式) 指令:
// 确保自定义样式与 Tailwind 的默认样式保持一致的优先级和顺序
@layer components {  
  .custom-component {
    // 将预定义的实用工具类bg-blue-500和text-white应用到.custom-component类上。
    @apply bg-blue-500 text-white;  
  } 
}

// 在其他地方就可以很方便使用 .custom-button 这个类名应用如下样式
.custom-button {  
  @apply py-2 px-4 bg-blue-500 text-white rounded;  
}

或开发 Tailwind 插件(跨项目复用):
// custom-plugin.js  
// 导入 Tailwind CSS 的插件模块  
const plugin = require('tailwindcss/plugin');  

// 导出插件函数  
module.exports = plugin(function({ addUtilities }) {  
    // 添加自定义的 CSS 工具类  
    addUtilities({  
        // 定义 .yun 类,设置背景颜色为蓝色,文字颜色为黄色  
        '.yun': {  
            background: 'blue',  
            color: 'yellow'  
        },  
        // 定义 .yun-text 类,设置字体大小为 70px  
        '.yun-text': {  
            'font-size': '70px'  
        }  
    })  
})

上面插件在 tailwind.config.js 里引入后,就可以在使用上面定义的类了:

/** @type {import('tailwindcss').Config} */
export default {
  content: ['./src/**/*.{js,ts,jsx,tsx}', './index.html'],
  theme: {
    extend: {}
  },
  plugins: [require('./custom-plugin')]
}

除此之外,还可以这样扩展:

module.exports = {
  theme: {
    extend: {
      // 自定义颜色
      colors: {
        'custom-blue': '#1da1f2',
        'custom-green': {
          light: '#4ade80',
          DEFAULT: '#22c55e',
          dark: '#16a34a',
        },
      },
      // 自定义字体大小
      fontSize: {
        'xxs': '0.625rem',
        '2xl+': '1.75rem',
      },
      // 自定义间距
      spacing: {
        '72': '18rem',
        '84': '21rem',
        '96': '24rem',
      },
      // 自定义断点
      screens: {
        'xs': '475px',
        '3xl': '1600px',
      },
    },
  },
  // 自定义变体
  variants: {
    extend: {
      backgroundColor: ['active'],
      textColor: ['visited'],
    }
  },
}

使用:

<div class="container mx-auto p-4">
    <!-- 使用自定义颜色 -->
    <h1 class="text-4xl font-bold text-custom-blue mb-4">欢迎使用扩展配置</h1>
    
    <!-- 使用自定义字体大小 -->
    <p class="text-xxs text-gray-500 mb-2">这是超小号文字</p>
    <p class="text-2xl+ text-gray-700 mb-4">这是略大于2xl的文字</p>
    
    <!-- 使用自定义间距 -->
    <div class="bg-custom-green p-72 mb-4">
        <p class="text-white">这个div有很大的内边距</p>
    </div>
    
    <!-- 使用自定义断点 -->
    <div class="xs:bg-red-500 sm:bg-blue-500 md:bg-green-500 lg:bg-yellow-500 xl:bg-purple-500 2xl:bg-pink-500 3xl:bg-orange-500 p-4 mb-4">
        <p class="text-white">这个div在不同屏幕尺寸下会改变颜色</p>
    </div>
    
    <!-- 使用自定义变体 -->
    <button class="bg-gray-300 hover:bg-gray-400 active:bg-custom-green-dark text-black font-bold py-2 px-4 rounded">
        点击我
    </button>
    
    <a href="#" class="text-blue-500 visited:text-purple-500">
        这是一个链接
    </a>
</div>

5 Tailwind 的实现原理

Tailwind 是一个基于 PostCSS 的插件,通过解析、转换和生成 CSS 代码。

它通过提取器(extractor)扫描 JS 和 HTML 文件中的类名,并基于这些类名生成最终的 CSS 代码。

tailwind 还有种叫 JIT 的编译方式,JIT 模式通过分析 HTML、JavaScript 和模板文件,识别出所有使用的 Tailwind 类,然后只生成这些类的 CSS。这种方法既保持了 Tailwind 的灵活性,又解决了传统方式下 CSS 文件过大的问题。

6 反对声音与解决方案

  1. 可读性与可维护性:通过 Tailwind CSS IntelliSense 插件提供智能提示,提升开发体验。
  2. 调试难度:在 Chrome DevTools 中可以直接查看样式,调试更方便。
  3. 类名冲突:通过添加前缀解决类名冲突。

这个插件触发提示需要先敲一个空格,这点要注意下。

7 总结

Tailwind 是一个高效、灵活的原子化 CSS 框架,简化了样式编写,避免了样式冲突,提升了开发效率。

通过配置文件和插件扩展,Tailwind 能适应各种项目需求。