基础样式必须仅用不含“--”的block和element类名(如.btn、.form-field__input)定义,覆盖字体、padding、border-radius等基线属性;修饰符(含“--”)专用于声明可由js控制的交互状态,如.btn--disabled、.form-field--invalid,且css规则须按基础类→修饰符→组合选择器顺序书写。

静态基础样式必须只用 Block 和 Element 类名
基础样式只能出现在 .btn、.form-field、.search-form__input 这类不含 -- 的类上。一旦出现 --,它就不再是“基础”,而是修饰符——哪怕你只是想临时加个 margin-top。常见错误是把尺寸、主题、默认边框等写进 .btn--large 或 .btn--primary 里,结果导致所有按钮都得带修饰符才能显示正常,破坏了“基础即可用”的前提。
基础样式应覆盖:字体、行高、默认 padding/margin、border-radius 基线、禁用伪类(如 :hover)的初始态。这些必须不依赖任何修饰符就能渲染出合理 UI。
-
.btn必须定义display: inline-flex、padding、font-size等,否则.btn--disabled单独使用会塌陷 - Element 类(如
.form-field__label)不能省略display或color,否则修饰符叠加后可能无样式可叠 - 禁止在基础类里写
transition:它属于状态变化行为,应由修饰符或伪类触发后才生效
交互状态只能用 -- 修饰符,且必须 JS 可控
所谓“交互状态”,是指能被 JavaScript 显式切换、且需持久保留的视觉反馈,比如 .btn--disabled、.form-field--invalid、.search-form__input--focused。它们不是浏览器自动加的 :hover,也不是 CSS 动画帧,而是你调用 el.classList.toggle('btn--disabled', isDisabled) 才出现的东西。
- 伪类(
:hover、:focus、:active)永远不参与 BEM 修饰符命名,也不该写成.btn--hover——那既不是合法修饰符,也无法响应真实交互 -
--focused这类修饰符必须由 JS 在focusin/focusout事件中手动添加/移除,不能靠:focus自动触发,否则 DevTools 里看不到状态来源 - 多个状态共存时(如
.btn--disabled.btn--loading),CSS 规则必须显式写出组合效果,不能指望层叠“刚好生效”
别把业务逻辑塞进修饰符名里
修饰符名要描述“它看起来什么样”或“它现在能做什么”,而不是“后台返回了什么”。.btn--network-error 是错的,.btn--error 也是模糊的;正确的是 .btn--failed(操作失败)、.btn--idle(待命)、.btn--submitting(正在提交)——这些词让前端、设计师、测试都能一眼对齐预期。
-
--pending不如--loading:前者无法推断是否禁用点击、是否有 loading 图标;后者明确含交互约束 -
--success要慎用:表单提交成功后按钮该恢复--idle,而不是一直挂着--success,否则后续点击会失效 - 布尔型状态建议用
--is-前缀,但仅限容器级不可拆分的状态,如.modal--is-open;按钮这类原子组件更倾向阶段词(--submitting>--is-submitting)
基础样式和修饰符的加载顺序直接影响表现
CSS 文件里,基础类规则必须写在所有修饰符规则之前。否则 .btn--disabled 定义的 opacity: 0.5 可能被后面 .btn 里的 opacity: 1 覆盖——因为两者权重相同,后写的赢。这不是 BEM 的问题,是 CSS 层叠本质决定的。
- 推荐结构:先写
.btn、.btn__icon,再写.btn--primary、.btn--disabled,最后写组合选择器.btn--disabled.btn--loading - 高频动态状态(如
--loading)建议放在文件末尾,避免被静态主题类(--primary)意外覆盖 - 不要依赖 class 添加顺序控制样式优先级:DOM 中
class="btn--loading btn"和class="btn btn--loading"效果完全一致,起作用的是 CSS 规则位置,不是 HTML 里 class 的顺序
BEM 里最易被忽略的一点:修饰符不是“开关”,而是“声明”。.btn--disabled 不代表“此刻被禁用”,而代表“这个按钮被设计为禁用态变体”——它可能在 SSR 输出里就存在,也可能由 JS 初始化后添加。能否点击、是否响应事件,必须由 JS 同步控制 disabled 属性和 class,二者缺一不可。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











