公共按钮类名必须唯一使用btn作为block名,显式声明所有样式属性并用rem单位,修饰符须单类名且互不干扰,子元素必须直系,确保任意上下文开箱即用。

公共按钮类名必须用 btn 作为唯一 Block 名,任何其他写法(button、primary-btn、nc-btn)都会破坏跨项目复用基础——它不是“要不要加前缀”的问题,而是 BEM 的语义契约要求 btn 是按钮这个 UI 单元的通用标识符。
为什么不能加业务前缀如 nc-btn
加前缀看似防冲突,实则让按钮失去“公共性”:nc-btn 和 ds-btn 在不同项目里无法共享同一份 CSS 文件或设计系统文档;当组件库升级时,所有引用处都要同步改前缀,而 btn 可以直接被 @import 或 CDN 加载后开箱即用。真正防冲突靠的是作用域隔离(CSS Modules / Shadow DOM),不是类名前缀。
btn 必须能脱离上下文独立渲染
常见错误是只定义 btn 的颜色和边框,却依赖父容器提供 font-size 或 display。这会导致:挪到弹窗里文字变小、嵌入 nav 后变成 inline 元素、在 rem 基准为 10px 的页面中 padding 失控。
-
btn必须显式声明display: inline-flex(或inline-block)、padding、font-size、line-height、cursor、border、vertical-align - 所有尺寸单位统一用
rem,禁用em和px -
line-height用无单位值(如1.4),不写1.4rem
修饰符叠加必须互不干扰
写成 btn btn--primary btn--disabled 后,禁用态没生效?大概率是 btn--primary 用了 !important,或者 btn--disabled 规则权重不够(比如写成了 .btn.btn--disabled)。
- 所有修饰符必须用单类名选择器:
.btn--disabled { },不加.btn前缀 -
btn--disabled必须显式重置:pointer-events: none、cursor: not-allowed、opacity(别只改背景色) - 禁止嵌套写法:
.btn--disabled:hover会拦截真实 hover 状态,导致禁用按钮意外响应鼠标移入
图标、加载态等子元素必须严格直系
btn__icon 不是可选装饰,而是按钮功能的一部分;如果 HTML 里写成 <button class="btn"><span class="btn__icon"></span>文本</button>,但 btn__icon 实际藏在 <div> 里,BEM 语义就断裂了。
<ul>
<li>
<code>btn__icon 必须是 btn 的**直系子节点**,不能隔层
btn--icon-left 这类块级修饰符,而非 btn__icon--left
btn__icon--loading,因为它描述图标自身状态(旋转、占位),不是按钮整体状态最易被忽略的一点:btn 的复用性不取决于命名多“规范”,而取决于它是否真的能在任意 HTML 上下文中插入后立即可用——不靠 JS 注入样式、不靠父容器兜底、不靠开发者手动补全缺失属性。一旦需要查文档才知道“这个按钮还缺什么才能显示正常”,说明它还没达到公共组件标准。











