📏 CSS 方法论(OOCSS / BEM / SMACSS / ITCSS)
一句话定性
CSS 的选择器天生是全局的——这在一篇文档里无害,在一个百人团队的大型应用里却是原罪。在没有任何技术手段隔离样式的年代,前端只能靠纯粹的人类约定来对抗混乱:用命名规范、分层架构、组合思想来”假装”CSS 有作用域和模块化。CSS 方法论,就是工具到位之前,人类用纪律换秩序的一段历史。
一、它们是什么 & 出现的时代
CSS 方法论是一组关于”如何组织和命名 CSS”的约定与最佳实践,流行于 2005-2013 Ajax时代后期到 2013-2018 SPA时代早期(约 2009–2016)。它们不是工具、不是库、不需要编译,纯粹是写法上的纪律。代表四套:
| 方法论 | 提出者 / 年份 | 核心思想 | 一句话 |
|---|---|---|---|
| OOCSS | Nicole Sullivan,2009 | 面向对象 CSS:结构与皮肤分离、容器与内容分离 | 把样式当”可复用对象” |
| BEM | Yandex(俄罗斯) | Block__Element—Modifier 命名 | 用长类名”伪造”作用域 |
| SMACSS | Jonathan Snook,2011 | 按角色把规则分成 5 类(Base/Layout/Module/State/Theme) | 给 CSS 分层归类 |
| ITCSS | Harry Roberts | 按 specificity 从低到高分层倒三角组织 | 驯服优先级与级联 |
二、为什么会出现:CSS 全局作用域引发的三场战争
大型项目里,全局 CSS 必然失控的三个机制
CSS 没有作用域、没有模块、没有命名空间。当代码量和团队规模增长,三种灾难必然发生:
- 命名冲突:你写
.button,同事也写.button,后加载的覆盖先加载的。改 A 页面的样式,B 页面莫名其妙崩了。没人敢删任何一行 CSS,因为不知道哪里还在用它(append-only CSS:只敢加不敢改)。- specificity 战争:为了让自己的样式”赢过”别人,大家比赛写更长更具体的选择器(
.header .nav ul li a.active)。优先级越堆越高,最后没人能覆盖谁。!important核武器:当 specificity 也卷不动了,就祭出!important。一旦有人用了,别人只能用更多的!important还击。这是 CSS 工程失控的最终症状——核平等于谁都别想活。
这三场战争的根因是同一个:CSS 的全局命名空间,在缺乏隔离手段时,把”局部决策”变成了”全局后果”。 方法论的全部努力,都是在用约定人为制造隔离。
三、核心机制 & 为什么各自流行
OOCSS(2009,Nicole Sullivan)—— 思想奠基者
Sullivan 把软件工程的面向对象思想引入 CSS,提出两条原则:
- 结构与皮肤分离:布局结构(尺寸、定位)和视觉皮肤(颜色、圆角)拆成独立的类,自由组合。
- 容器与内容分离:
.title的样式不该依赖它在.sidebar里还是.main里——样式应可移植。
OOCSS 的历史地位
它本身没有严格的命名规范,但它第一次把”复用”和”组合”作为 CSS 的第一性原则提出来。这个”用小的、可组合的类拼出界面”的思想,直接是日后原子化 CSS的精神祖先。
BEM(Yandex)—— 用命名”伪造”作用域
BEM 是流传最广、最实用的一套。它规定类名必须是 block__element--modifier 形式:
.card { } /* Block:独立组件 */
.card__title { } /* Element:组件的一部分 */
.card__title--large { }/* Modifier:变体 */
BEM 为什么赢了:它最直接地攻击了"作用域"痛点
类名
.card__title长到几乎不可能和别人撞车,等于用命名约定手工模拟了命名空间。而且它强制扁平的单层选择器(永远只用一个 class,不嵌套),从源头杜绝了 specificity 战争——所有规则优先级都一样,谁后写谁生效,简单可预测。BEM 的成功证明:当时大家最痛的不是复用,而是冲突。
SMACSS(2011)与 ITCSS —— 治理”级联”本身
如果说 BEM 管”单个名字”,SMACSS 和 ITCSS 管的是”整个代码库怎么分层”:
- SMACSS 把所有规则按角色分成 Base / Layout / Module / State / Theme 五类,各司其职。
- ITCSS 更进一步,按 specificity 从低到高排成一个”倒三角”层级(从通用的 reset 到具体的覆盖),从架构上保证”低优先级的在前、高优先级的在后”,让级联可控、可预测。
它们流行,是因为在 SPA 之前,CSS 缺乏任何架构层面的组织方式,大团队迫切需要一套”放东西的规矩”。
四、带来的新问题 / 副作用
约定的根本脆弱性:它靠人自觉
方法论本质是社会契约,而非技术强制。它的所有问题都源于这一点:
- 没有强制力:编译器不会因为你不写 BEM 就报错。团队里只要有一个人偷懒、有一个新人不懂规范,体系就开始腐烂。约定的执行成本完全压在 code review 和团队自律上。
- 类名臃肿、心智负担重:
block__element--modifier__sub--state这种长名字写起来啰嗦,记起来累。HTML 里class="card card--featured card__body card__body--large"也不好看。- 无法删除死代码:即便用了方法论,你依然无法确定一条 CSS 还有没有被用到——全局作用域的根本问题没有被消除,只是被”绕过”了。
- 复用与冲突的矛盾没真正解决:BEM 用”不复用名字”换”不冲突”,代价是几乎放弃了跨组件的样式复用。
五、为什么会衰落 / 现状:从”约定”到”工具”的范式转移
方法论的死穴:它在解决一个本该由工具解决的问题
方法论被三波工具化方案逐步取代:
CSS 全局作用域(命名冲突 + specificity 战争 + !important)
│
├──【人治阶段】用约定对抗(2009–2016)
│ OOCSS(组合思想)→ BEM(命名伪作用域)
│ → SMACSS / ITCSS(分层治理级联)
│ 痛点:靠人自觉,规模一大就失守
│
▼
【法治阶段】用工具消灭(2015 起)
├─ CSS Modules:编译期把类名 hash 成唯一值
│ → "真·局部作用域",根本不用再手写 BEM → [[CSS-in-JS]]
│
├─ CSS-in-JS:样式直接写进组件,作用域天然隔离 → [[CSS-in-JS]]
│
└─ 原子化 CSS:根本不命名,直接用预定义 utility 类 → [[原子化CSS]]
(OOCSS"组合"思想的工业化终点)
方法论留下了什么(它没有白死)
- OOCSS 的”组合优于继承”思想,在 原子化里以工业化形式复活——utility class 就是把”小而可组合的对象”做到极致。
- BEM 的”局部作用域意图”,被 CSS Modules 用编译期 hash 自动实现了——人想做的事,机器替你做了。
- ITCSS 对级联的治理思想,最终被 CSS 原生的
@layer(级联层) 标准化收编——又一次”社区先发明,标准后追认”。方法论是一段”工具缺位时,人类用纪律硬扛”的过渡史。它没有失败,只是完成了历史使命:它精确地定义了问题,后来的工具才能精准地解决问题。
🔗 同组:CSS演进史 | 布局演进史 | CSS预处理器 | CSS-in-JS | 原子化CSS 🔗 相关:2005-2013 Ajax时代 | 2013-2018 SPA时代 | Webpack | jQuery