告别 CSS 噩梦:从 Tailwind CSS 到 DOM 性能优化的深度思考

47 阅读4分钟

今天尝试 面向对象 CSS。封装基类,利用多态处理业务差异,通过组合形成新类。

原子化 CSS,也就是今天的主角 —— Tailwind CSS。本篇文章基于react实现。

为什么选择了 Tailwind CSS?

Tailwind CSS 的核心理念是将 CSS 规则拆分成最小的“原子”。

就像tailwindcss 官网主页说的:

image.png

主打 “不离开 HTML 即可快速构建现代网站”,适合快速原型开发与自定义设计。

  1. 极致的复用:它提供了海量的基类,我们可以像搭积木一样自由组合。
  2. 拥抱 AI 时代:最近在研究 LLM(大语言模型)辅助编程,我发现 Tailwind 特别友好。因为它的类名语义化极强,Prompt 描述布局时,AI 生成的代码非常准确。

一、tailwindcss 配置

这里可以去 tailwindcss 官网查看,我这里就简单过一遍。

1. 安装 tailwindcss 和vite 插件

npm install tailwindcss @tailwindcss/vite

2. vite.config.js 配置

import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    tailwindcss(),
  ],
})

image.png

3. 导入 tailwindcss

@import "tailwindcss";

image.png

4. 使用

后面我们就可以在App.jsx中直接使用tailwindcss了。

二、实战:从布局到组件

在我的项目中,Tailwind 让响应式布局和组件开发变得异常简单。

1. 移动优先的响应式布局

看在这个 App.jsx 的例子,我需要实现一个经典的“主内容 + 侧边栏”布局。

export default function App() {
    // Mobile First 策略
    // 默认是 flex-col (垂直排列),适配移动端
    // md:flex-row (中等屏幕以上水平排列),适配 PC 端
    return (
        <>
            <div className="flex flex-col md:flex-row gap-4">
                <main className="bg-blue-500 p-4 md:w-2/3">
                    主内容
                </main>
                <aside className="bg-gray-200 p-4 md:w-1/3">
                    侧边栏
                </aside>
            </div>
        </>
    )
}

image.png

image.png

注意 md: 前缀。Tailwind 默认采用 Mobile First(移动优先)策略。我们首先定义移动端的样式(flex-col),也兼容了 PC 端的基础样式。然后通过 md:flex-row 告诉浏览器:“当屏幕宽度大于 md 断点时,切换成水平排列”。这比手写 @media 查询要优雅太多了。

2. 组件封装与交互状态

再来看看 App2.jsx,我们可以把一堆 utility classes 封装成一个 React 组件,同时轻松处理 hover 等状态。

const ArticleCard = () => {
    // JSX + tailwindcss(UI 的一部分) = UI
    return (
      <div className="p-4 bg-white rounded-xl shadow hover:shadow-lg transition">
        <h2 className="text-lg font-bold">Tailwindcss</h2>
        <p className="text-gray-500 mt-2">
          用utlity class 快速构建UI
        </p>
      </div>
    )
}

export default function App() {
  return (
    <>
      <h1>111</h1>
      <h2>222</h2>
      <button className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-red-700">提交</button>
      <button className="px-4 py-2 bg-blue-300 text-black rounded-md hover:bg-gray-400">默认</button>
      <ArticleCard />
    </>
  )
}

image.png

这里 hover:shadow-lgtransition 配合,一行代码就实现了卡片的悬停浮起效果。我们不需要为一个简单的交互去写单独的 CSS 类。

3. 不满意,那就改

tailwind.config.jsTailwind CSS 的配置文件,用于自定义和扩展 Tailwind 的默认行为

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/**/*.{html,js,jsx,ts,tsx}", // 告诉 Tailwind 去哪些文件里扫描用到的 class
  ],
  theme: {
    extend: {
      colors: {
        brand: '#38bdf8', // 自定义颜色:text-brand, bg-brand
      },
      spacing: {
        '128': '32rem', // 自定义间距:p-128, m-128
      },
      fontFamily: {
        sans: ['Inter', 'sans-serif'], // 修改默认无衬线字体
      }
    },
  },
  plugins: [
    require('@tailwindcss/forms'), // 引入官方插件
  ],
}

⚠ 即使没有创建 tailwind.config.js 文件,Tailwind CSS 依然可以正常工作( 有 默认配置)。

三、延伸:从“样式碎片”到“文档碎片”

当我们用 Tailwind 把 CSS 拆解成原子级的“碎片”来优化样式管理时,我不禁联想到在 DOM 操作层面,我们其实也有类似的概念 —— Fragment(片段)

App2.jsx 中,你可能注意到了这个写法:

export default function App() {
  return (
    // Fragment: 临时的容器,不会渲染到 DOM 中
    <>
      <h1>111</h1>
      <h2>222</h2>
      <ArticleCard />
    </>
  )
}

深入 DocumentFragment

在 React 中,我们使用 <></>(Fragment)来包裹组件,目的是为了维持树状结构便于遍历,也就是解决单一根节点限制的问题,同时不渲染额外的多余 div 节点

但在原生 JavaScript 的底层,这个概念其实对应的是 DocumentFragment(文档碎片节点)。它不仅仅是为了“不渲染多余标签”,更是为了性能优化

来看一段原生 JS 的对比:

const container = document.querySelector('.container');
const p1 = document.createElement('p');
const p2 = document.createElement('p');

// ❌ 普通做法:多次操作 DOM
// container.appendChild(p1); // 触发一次重排/重绘
// container.appendChild(p2); // 又触发一次

// ✅ 性能优化做法:使用 Fragment
const fragment = document.createDocumentFragment(); 
fragment.appendChild(p1); // 先挂载到内存中的碎片上
fragment.appendChild(p2);

// 一次性挂载,只触发一次浏览器的渲染流程
container.appendChild(fragment); 

DocumentFragment 提供了一个轻量级的文档对象。可以把它当做一个隐形的“暂存区”。所有的 DOM 操作都在这个暂存区(内存)里完成,最后我们只需要把这个暂存区一次性贴到页面上。

这和 Tailwind 的理念在某种程度上是殊途同归的:

  • Tailwind:通过原子类组合,避免了像传统 CSS 那样生成大量重复、冗杂的样式表,让 HTML 结构更纯粹。
  • Fragment:通过内存批处理,避免了频繁的 Real DOM 交互,让页面渲染更高效。

oUDEHFffBGyn1aCOrrLDADIIjB5UAurelAENAZ~tplv-0wx4r9yasq-awebp-resize_640_640.webp