合法的bem类名结构为block__element--modifier三段式,如menu、menu__item、menu--active、menu__item--disabled;禁止数字开头、多重下划线、混合分隔符或连字符非法位置,允许多个修饰符连续(如menu__item--hover--dark)但禁止短横连接(如menu__item--hover-dark)。

什么是合法的BEM类名结构
BEM要求类名由块(block)、元素(element)和修饰符(modifier)三部分按固定格式组合,典型形式如 menu、menu__item、menu--active、menu__item--disabled。它不允许多重下划线、连字符开头/结尾、相邻连字符或混合分隔符(比如 menu__item--hover--dark 是合法的,但 menu__item--hover-dark 不是)。正则必须守住这几个边界条件。
匹配单个BEM类名的正则表达式
用这个正则能一次性捕获完整合法类名:
^[a-zA-Z][a-zA-Z0-9]*(__[a-zA-Z][a-zA-Z0-9]*)?(--[a-zA-Z][a-zA-Z0-9]*)*$它分三段:开头是字母打头的块名;中间可选
__ + 元素名(同样字母开头);结尾可选 -- + 修饰符名。注意这里没允许数字开头,因为 BEM 规范明确要求块名必须以字母开始。常见错误现象:123menu、menu__、menu--、menu__item-- 都会被拒绝;menu__item--hover--dark 是合法的(多个修饰符允许),但 menu__item--hover-dark 会失败——因为中间用了短横而非双短横。
在JavaScript中验证CSS类名是否符合BEM
直接调用 test() 或 match() 即可,别忘了加 ^ 和 $ 锚定全字符串:
const bemRegex = /^[a-zA-Z][a-zA-Z0-9]*(__[a-zA-Z][a-zA-Z0-9]*)?(--[a-zA-Z][a-zA-Z0-9]*)*$/;
bemRegex.test('header__logo--large'); // true
bemRegex.test('header__logo--large--dark'); // true
bemRegex.test('header__logo--large-dark'); // false(不是双短横)
bemRegex.test('header__logo__icon'); // false(不允许两个 __)
bemRegex.test('--invalid'); // false(不能以 -- 开头)
性能上没问题,现代 JS 引擎对这种长度固定的正则优化很好;但要注意:这个正则不处理空格或多个类名混在一起的情况——它只校验单个类名。如果要校验整行 HTML 的 class 属性,得先用 split(/\s+/) 拆开再逐个测。
为什么不用更宽松的正则(比如忽略首字母限制)
有些项目会放宽为“字母或数字开头”,但这就破坏了 BEM 可读性和工具链兼容性。比如 PostCSS 插件 postcss-bem-linter 和 VS Code 的 BEM 插件都严格检查首字符。实际踩过的坑包括:
- CI 构建时 linter 报错,但本地正则没拦住,因为本地用了宽松版
- 自动补全插件无法识别
1button__text,导致 IDE 不提示子元素 - 构建产物中生成的 CSS 选择器优先级意外升高(数字开头类名在某些旧浏览器解析异常)
真正麻烦的不是写正则,而是团队里有人悄悄绕过规范加了个 btn2__icon,然后三个月后没人记得这算不算 BEM —— 所以正则越严越好,宁可早期报错,别留模糊地带。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











