SANSUI'S BLOG

系统外观
分类标签
RSS
Sansui 2025
All rights reserved
人活着就是为了卡卡西

踩了一圈 CSS 构建方案的坑

7 月 12 日, 2025

css 的写法一直算比较混乱的。层叠的样式表与 DOM 结构的分离看似清晰,但也因此容易产生屎山,组合太自由,哪些选择器用了哪些选择器没用,共用的嵌套的,分离的。今天小编就带你一探究竟(……)

CSS类复用粒度

我自己把 css 选择器(类)的复用粒度分三个层级。

组件类

粒度最大的层级,通常按组件级别语义化。选择器一般是下面这些名字

.wrapper
.container
.list-item

组件化的选择器下面通常有很多条的 css。

功能类

通常是共用的样式或状态,比如

.open
.close
.light
.dark
.glass-effect

这个看起来好像和组件类不冲突,但硬说的话组件类其实应该是这样

.container.open { 此处将 .open 的所有样式全覆盖 }
.container.close { 此处将 .close 的所有样式全覆盖 }
.container.light { 此处将 .light 的所有样式全覆盖 }
.container.dark { 此处将 .dark 的所有样式全覆盖 }

组件类的状态严格在组件的 scope 下。功能类则是可以不限 Scope 的复用。

这 CSS 容易混乱的根源。在工程维护角度,功能类是最不敢乱动的类,不知道动了后哪里样式就会出问题。但在设计角度,用功能类复用一些状态又确实很方便,统一设计也好用。比如增加统一的圆角、描边、阴影样式。

功能类的优缺点是一体两面——图像的只有主观的好看与否,没有客观的对错。

原子类

定义海量常用的基础样式类,在 class 上直接写类名就能获得对应效果。就是 tailwind css。

原子类相较于功能类粒度更小,也不会轻易改动 css 属性。

.flex
.col-1
.text-sm

方案

通常来说,一个库的样式会着重在一个某一个粒度上。

原生 css

用原生 css 时通常会以 组件化 的粒度为主,带极少的功能类。现在配合 css 变量使用。早期的网页简单,一个 CSS 文件就能搞定全站,设计上并没有考虑项目变得越来越复杂后的实践。

优点:性能好,扁平的结构利好小项目。适合写研究新样式。

缺点:过于扁平,大量工程化后易屎山,存在样式与 DOM 分离带来的维护混乱。

SCSS

古法预处理器,可能多层嵌套 css,可组合。是 组件化 的粒度。在 CSS.module 出来前,用 SCSS 分割 Scope 挺好用。

优点:结构非常清晰

缺点

  1. 编译后的选择器很长一串,从浏览器渲染角度,匹配DOM是耗性能的
  2. 难以应对复杂项目 DOM 结构的改变,需要考虑扁平化 + 命名,但这样做和原生 CSS 的维护体验也不相上下。

CSS Module

CSS Module 是完全 组件化 的粒度。相比起 SCSS 的样式与 DOM 分离,CSS Module 为组件内部样式耦合,组件间样式分离。

优点: 在组件粒度分割合理的情况下,清晰易维护。

缺点:依赖预构建,写类名写起来太磨叽了。整体我用得不多没法评价。

BootStrap

组件化 为主,少量原子化修饰的预置样式库,拿来即用是不错的。早期 CSS 框架大多是指预制样式,和预构建的库有本质区别。

Tailwind css

完全原子化的神奇之库,通过编译可以有功能类和组件类。它更像是重新定义了 css 语法。

优点

  1. 灵活,快,好看
  2. 工具链齐全,可以裁剪掉不用的原子类。

缺点

  1. 稍微要写复杂一点的样式,DOM 就会被一大堆 class 埋没。
  2. 从浏览器渲染角度,匹配、合并大量 CSS 样式是需要更多性能开销的
  3. 要做到同种样式的复用,必须组合原子类,变成功能类或组件类,否则维护起来相当麻烦。这似乎违背了用 tailwind css 的初衷,熟悉了 css 的不如直接自己用 css 手撮功能类和组件类。
  4. 其实我是 tailwind 黑,嗯。但无法否认开发时确实很快很方便。

原生 css in js

指 JS Object 转译为 CSS。由于写起来太不像 CSS,复杂的功能写起来过于不直观 ,我直接 PASS。

Styled-components

组件化的 CSS in JS 方案,写起来像 CSS 实际是 JS。支持客户端动态修改 CSS 具体属性(其他方案做状态改变主要依靠 selector 的匹配)

优点

灵活好拓展,比如主题管理不仅仅是颜色,还可以是图片资源一类的。

缺点

  1. 因为是 JS 转 CSS,服务器编译慢和客户端渲染慢得选一个
  2. React 的 useContext 要被废弃了,而 styled-components 严重依赖此 hook,导致进入了维护状态。JS 框架发展太快了。

Linaria

自定义 功能类 的 CSS in js 方案,同时也支持 组件化 写法

优点

是预构建方案,和原始的 CSS 写法和思路差不多。

缺点

  1. 组件化鸡肋, 功能类和组件化过于割裂,反而使得组件化样式管理困难(比如组件样式和自定义原子样式写两个地方,加上DOM 上写 classname,等于写个样式得看三个窗口)
  2. 使用功能类有点像原子化,又完全不如 tailwind 已经给你预设好一堆东西的效率。写类名和 cssmodule 一样,太磨叽了

总之有点四不像。

构建组建库

每一个 CSS 方案都有对应的构建组件库的实践。 shadcn 是基于 tailwind 构建组件库实践。

CSS 框架选择要素

  1. 样式复用
  2. 样式组合
  3. 动态样式
  4. 主题切换
  5. 代码提示
  6. 自动裁剪
  7. 随意重构
  8. 渲染性能
  9. 实践的统一性

最重要的还是自己的需求。

更新于 2025-07-12 20:49
Waline