应改用bem类名替代嵌套:禁止多层后代选择器,确保每个bem类独立生效、modifier属block、子元素超两层须拆新block,&后不可空格,保留嵌套需严格限于主题、响应式且深度≤2,并通过ci扫描拦截空格选择器。

直接删掉嵌套,改用 BEM 类名。多层嵌套不是写法问题,是结构耦合的显性症状——你改一个 HTML class,三处 CSS 要同步动,DevTools 里找不到谁在覆盖 .card .header .title,这就是维护灾难的起点。
为什么 .header .nav .item 这类选择器会让改样式像拆炸弹
浏览器匹配是从右往左的,.item 被反复回溯父级,DOM 越深、更新越频繁,重绘开销越明显;人脑却从左往右理解结构,这种错位让定位失效原因变得反直觉。更实际的是:
- 删掉中间某层 wrapper(比如
.nav改成.main-nav),整条规则静默失效,DevTools 甚至不报“未匹配” -
document.querySelector('.header .nav .item')这类 JS 代码会同步断裂,但没人会去搜 JS 文件里的选择器字符串 - 新人看到
.layout .main .content .card .title,第一反应是“这不能动”,而不是“它本不该存在”
用 BEM 替代嵌套时,必须守住的三条线
BEM 不是加长类名,是把作用域编码进名字里。真正起效的前提是严格约束写法:
- 禁止出现
.card .card__title——.card__title必须独立生效,不依赖任何父级 -
.card__title--dark是错的,Modifier(--dark)属于 Block(.card),应写作.card--dark .card__title - 不允许
.card__title__icon,深度超限说明该拆新 Block,比如.card__title-icon或独立的.icon
Less/Sass 嵌套里 & 的坑:空格决定权重
& 不是视觉缩进的延续,它是上一层选择器的完整字符串副本。有无空格,输出结果天差地别:
- 错:
.modal { & .close { opacity: 0.5; } }→ 编译出.modal .close(多一层后代,权重+1) - 对:
.btn { &__icon { display: inline-block; } }→.btn__icon(权重恒为 0-1-0) -
&后**不能有空格**,否则等于主动加权;要拼接就写&__xxx或&--modifier - 子元素必须显式用
>:.card { > .header { > h1 { } } }→.card > .header > h1,比.card .header h1更短、权重更低
哪些嵌套还勉强能留,但得加锁
完全禁用不现实,但必须设防:
- 主题切换:
.theme-dark .button可接受,因为 dark 是全局上下文,不是某块 HTML 的私有属性 - 响应式断点内限定:
@media (max-width: 768px) { .sidebar .menu-item { display: none; } }仅限布局收束,且深度 ≤ 2 层 - 伪类组合必须抽离:
@at-root跳出嵌套,避免@media里再套三层,否则每条规则都带全前缀,体积和权重双爆炸 - 所有保留的嵌套,都要过 CI 检查:
grep -r "\.[a-z]\+ \.[a-z]" src/css/扫描含空格的选择器(即含嵌套)
真正难的不是写出 .card__title,而是当产品临时要求“把卡片标题挪到侧边栏”,你能否不改一行 CSS 就让它正常显示——那才是嵌套被真正斩断的时刻。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











