BEM选择器更快是因为单类名(如.user-card__avatar--loading)支持浏览器一次哈希查找,而嵌套选择器(如.user-card .avatar)需从右往左逐层回溯父节点,DOM越深性能差距越显著。
因为BEM不是“过时的命名习惯”,而是解决 CSS 类名语义模糊、作用域失控、协作成本飙升这三类问题的最小可行方案——它不依赖构建工具,不绑定框架,也不靠运行时魔法,只靠命名本身把“谁的、什么、什么状态”三个问题塞进类名里。
BEM 的性能优势不来自名字长短,而来自单类名选择器一次哈希查找。比如 .user-card__avatar--loading 是浏览器直接查 class 表;而 .user-card .avatar 会让浏览器先找所有 .avatar 元素,再逐层向上检查父级是否匹配 .user-card,DOM 越深越慢。
.user-card { &__avatar { } } 安全;但写 .user-card { & .user-card__badge { } } 就会编译出带空格的选择器grep -r ".[a-z]+ .[a-z]" dist/ 快速揪出残留的空格选择器.user-card 对应 UserCard.vue 或 UserCard.jsx,Block 名就是组件名直译,目录、文件、类名三者一致,新人看类名就能反推组件位置。
.card .header 这类嵌套选择器,父组件 DOM 结构微调(比如加 wrapper)不会导致子组件样式失效user-card__avatar 这种类名就是唯一契约,不靠哈希、不靠 scope 属性payment-button__icon--disabled 天然带命名空间,不会和宿主项目冲突规范写得再好,只要这三点没守住,BEM 就退化成“带下划线的普通 CSS”:
立即学习“前端免费学习笔记(深入)”;
class="user-card user-card--loading",但 CSS 只定义了 .user-card--loading,漏掉基础块样式,删 modifier 整个组件就崩user-card__avatar 放到非 user-card 容器里,或写成 user-card__header__title(BEM 不允许 Element 嵌套 Element)button--width-200px 这类含具体值的类名,换单位或加媒体查询就得新增一堆类,违背“修饰符描述状态”的原则真正难的不是写对一个类名,而是每次写 __ 和 -- 时都得问自己:这个元素是不是它所属 Block 的固有部分?这个修饰符是不是可枚举、可复用、不带硬编码值的状态?——这种判断没法自动化,只能靠人盯住。