bem命名规范不直接作用于matches(),但通过提升html、css、js三端类名一致性,使matches('.button--primary.is-loading')等调用更直观可维护;其核心在于语义明确、层级扁平、修饰符归属清晰,并需避免模糊匹配、混用类名及字符串拼接。

大厂中高阶项目里,BEM 命名规范本身不直接作用于 matches(比如 CSS Selector 匹配逻辑或 JS 中的 Element.matches()),但它能显著提升与之强关联的 HTML 结构、CSS 类名和 JS 选择器的一致性,从而让 matches 调用更直观、可读、可维护。
为什么 BEM 让 matches() 调用更清晰
BEM(Block–Element–Modifier)强制将 UI 拆解为语义明确、层级扁平、无依赖的单元。当 JS 使用 element.matches('.button--primary.is-loading') 时,类名本身就表达了「这是一个按钮块的主样式变体,且当前处于加载状态」——无需翻看 HTML 或 CSS 就能理解意图。
对比模糊命名:element.matches('.btn.active.loading') 中 active 和 loading 含义重叠、来源不明、易冲突;而 BEM 下 .button--primary.is-loading 的修饰符归属明确(--primary 属于 Block 变体,is-loading 是布尔状态),逻辑自洽。
在 matches 中精准匹配 BEM 类名的关键实践
-
只用完整、确定的类名匹配:避免通配(如
.button__*)或模糊前缀(如[class^="button"])。BEM 的价值在于显式性,matches('.card__header.is-expanded')比matches('[class~="is-expanded"]')更安全、可读。 -
区分
is-与--语义:状态类(is-loading,is-disabled)用于运行时动态切换,适合matches()判断交互状态;样式变体(button--small,input--search)通常静态存在,一般不用于逻辑判断,除非需做视觉策略分支。 -
避免嵌套结构干扰 matches 判断:BEM 主张“一个元素一个类”,不依赖父子关系。因此不要写
el.parentElement.matches('.modal .content'),而应给内容区赋予独立块名,如.modal-content,再用el.matches('.modal-content')—— 简洁、稳定、可测试。
配合现代工具链增强可读性
在 TypeScript + React/Vue 项目中,可进一步固化 BEM 与 matches 的一致性:
- 定义类型常量:如
const LOADING_STATE = 'is-loading' as const;,再用于el.matches(`.button__trigger.${LOADING_STATE}`),支持 IDE 自动补全和重构校验。 - 封装语义化判断函数:例如
isButtonLoading(el: Element) { return el.matches('.button__trigger.is-loading'); },把 BEM 细节封装起来,上层逻辑专注业务语义。 - 结合 CSS Modules 或 scoped style,确保 BEM 类名不会意外泄漏或被覆盖,使
matches的结果真正反映组件当前真实状态。
警惕常见反模式
即便采用 BEM,以下做法仍会削弱 matches 的可读性:
- 混用非 BEM 类名(如遗留
.red-text或框架类uk-button)参与判断,破坏命名体系统一性; - 在 JS 中拼接 BEM 字符串(
el.matches(`${block}__${elem}--${mod}`)),不仅易错,还绕过编译期检查; - 用
matches替代状态管理:例如频繁靠el.matches('.tab.is-active')判断当前 tab,不如监听事件或读取数据源状态——BEM 类名是视图副产品,不是状态真相。










