样式为什么越写越乱
项目早期样式很好写,几个文件、几个类名,改起来很顺手。可随着页面增多、组件变多、人员更替,全局样式互相覆盖、!important 到处救火、同一个颜色出现在十几个文件里,就进入了「改一处坏三处」的恶性循环。
样式乱的本质是缺约束:没有统一的颜色和间距来源,没有明确的命名规则,没有模块边界。CSS 全局作用域的特性,让任何一处没有约束的写法都可能影响别处。
工程化不是引入多少工具,而是建立三层秩序:数值统一(变量与令牌)、命名统一(BEM)、边界统一(模块化与隔离)。这三点立住了,样式规模再大也能保持可维护。
CSS 本身不难,难的是让成千上万行样式长期不乱。
- CSS 变量数值统一与主题切换。
- BEM可读的类名命名。
- 预处理器嵌套、混入与模块化。
- 设计令牌设计与代码之间的桥梁。
CSS 变量与主题化
CSS 自定义属性(变量)把散落各处的魔法值收敛到一处。颜色、间距、圆角、字体都定义为变量,组件里只引用变量名,改一处全局生效。
:root {
--color-primary: #1E5FA8;
--space-md: 16px;
--radius-md: 8px;
}
.button {
background: var(--color-primary);
padding: var(--space-md);
border-radius: var(--radius-md);
}
变量的另一个大价值是主题化:主题只是变量集合的替换。在 html 上加一个 data-theme 属性,覆盖一组变量,整个站点的配色就切换了,组件代码一行不用改。
变量还天然支持作用域覆盖,组件内部可以按需重定义局部变量,实现灵活又受控的定制。
BEM 命名规范
BEM 把类名分成三部分:Block(块)、Element(元素)、Modifier(修饰符),分别用双下划线和双连字符连接。类名自带结构信息,不用看 HTML 也能猜到层级。
.card
.card__title
.card__image
.card--featured
块是独立组件,元素属于块的一部分,修饰符表达状态变化。这套命名让选择器天然扁平,几乎没有嵌套,特异性低,覆盖和复用都容易。
BEM 不强制嵌套缩进,配合 CSS 变量使用,能写出可读性和性能都不错的样式。团队统一这套规则,代码评审时类名就能反映意图。
预处理器与模块化
SCSS 这类预处理器带来嵌套、变量、混入和文件拆分,让 CSS 有了编程语言的表达能力。文件按模块拆分,再统一入口引入,样式结构和组件结构一一对应。
// variables.scss
$color-primary: #1E5FA8;
// button.scss
.button {
&--primary { background: $color-primary; }
&:hover { opacity: 0.9; }
}
嵌套要克制,层级超过两层就要警惕。预处理器负责的是「写的时候省事」,最终产出的仍是标准 CSS,所以性能优化依然要以产物为准。
现代 CSS 已经支持很多预处理器的能力(嵌套、变量),新项目可以优先用原生 CSS,把预处理器留给确实需要混入等高级特性的团队。
设计令牌体系
设计令牌是设计与代码之间的约定:设计稿里的色板、字号、间距,以统一的 token 命名进入代码。设计师改 token 定义,前端不用逐个组件改样式。
{
"color": {
"primary": { "default": "#1E5FA8" },
"surface": { "default": "#FFFFFF" }
},
"space": {
"sm": "8px", "md": "16px", "lg": "24px"
}
}
令牌通常分层:基础令牌(原始值)和语义令牌(按用途引用基础令牌)。组件只消费语义令牌,换主题时只需替换基础层,语义保持不变。
令牌可以用工具生成 CSS 变量、SCSS 变量甚至 Tailwind 配置,一份定义多处消费,避免各写各的导致漂移。
样式隔离方案
多团队协作、微前端、第三方组件接入时,全局样式互相污染是常见问题。样式隔离有几种成熟思路:CSS Modules 把类名编译成带哈希的局部名,作用域天然隔离。
// 组件内
import styles from './card.module.css';
// 产物
.card__title__3x2f { /* 带哈希的局部类名 */ }
CSS-in-JS(如 styled-components)把样式和组件绑定,运行时生成标签类名,隔离更彻底;Shadow DOM 则从浏览器层面隔离样式和 DOM,是 Web Components 的天然方案。
隔离方案各有取舍:CSS Modules 编译期解决、无运行时开销;CSS-in-JS 灵活但影响渲染性能。选型要看团队和场景,不必追求最前沿。
CSS 工程化落地清单
- 颜色、间距、字号全部收敛到变量,禁止魔法值。
- 类名统一 BEM,选择器保持扁平低特异性。
- 样式文件按模块拆分,入口统一引入。
- 建立设计令牌,设计与代码共用同一份定义。
- 多团队或微前端场景引入样式隔离。
- 定期清理无效样式,保持包体积可控。
好的样式体系,让新人第一天就能写出不破坏别人的代码。