__和--不能替换,因为工具链依赖其正则识别块、元素与修饰符;替换会导致lint报错、emmet失效、css-in-js解析失败;块名内-是唯一可配置且必须使用的连接符。

不能随意自定义 BEM 的连接符,__ 和 -- 是硬性约定,不可替换;但块名内部的连字符 - 可以统一配置,且必须用 -。
为什么 __ 和 -- 不能换成别的符号
BEM 规范中 __(双下划线)和 --(双连字符)是语义标记,不是风格偏好。工具链(如 stylelint-config-bem-stylint、VS Code 的 BEM 插件、PostCSS BEM 插件)全部依赖正则 ^[a-z][a-z0-9]*(-[a-z0-9]+)*$ 识别块名,并严格按 __ 切分元素、按 -- 提取修饰符。一旦改成 _ 或 -,会导致:
- lint 工具报错:
Expected element name to contain "__" - Emmet 补全失效:输入
.card+ Tab 不再自动展开.card__header - CSS-in-JS 库(如
clsx+bem-cn)解析失败,block('card').elem('header')输出card_header而非预期类名
块名中的 - 是唯一可配置的“连接符”,且必须用
多单词块名只能用 -(中划线),例如 user-profile✅,userProfile❌(CSS 非法),user_profile❌(与修饰符混淆)。你可以在 SCSS 中统一声明命名空间和分隔符变量:
$namespace: 'ui' !default; $block-sel: '-' !default; $elem-sel: '__' !default; $mod-sel: '--' !default;
然后封装混入:
@mixin b($name) {
$B: #{$namespace + $block-sel + $name};
.#{$B} {
@content;
}
}
@mixin e($name) {
$E: #{$selector + $elem-sel + $name};
@at-root .#{$E} {
@content;
}
}
调用时保持语义完整:
@include b('user-profile') {
@include e('avatar') {
width: 40px;
}
@include e('bio-section') {
margin-top: 12px;
}
}
输出为 .ui-user-profile__avatar 和 .ui-user-profile__bio-section,不漏掉 -,也不误把 bio-section 当成新块。
常见踩坑点:试图用变量控制 __ 或 --
有人想写 $elem-sep: '__' 然后 #{&}#{$elem-sep}title,看似灵活,实则埋雷:
- 团队新人可能传入
$elem-sep: '_',产出.card_title,被 lint 拦截或工具忽略 - IDE 无法静态分析类名结构,跳转定义、重命名全部失效
- 组件文档生成器(如 Styleguidist)靠固定模式提取
__,换符号就丢失元素列表
真正需要“定制”的,只有命名空间($namespace)和块名拼写规则(必须含 -),其余两个符号必须原样保留。
最易被忽略的是:块名里的 - 和元素名里的 - 语义不同——前者是块名组成部分,后者只是元素内部单词分隔,不影响 BEM 层级。比如 user-profile__bio-section 中,bio-section 是一个元素名,不是 bio 块加 section 元素。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











