btn 是唯一 block 名,须显式声明 display、padding、font-size 等全部样式,单位统一为 rem;修饰符如 btn--disabled 必须单类名、互不干扰;btn__icon 须为直系子节点,布局由块级修饰符控制。

必须用 btn 作为唯一 Block 名,所有样式显式声明、单位统一为 rem、修饰符互不干扰——否则所谓“复用”只是假象,一挪地方就失效。
为什么 btn 不能加业务前缀(如 nc-btn 或 ds-btn)
加前缀看似防冲突,实则直接废掉跨项目复用能力:nc-btn 和 ds-btn 无法共享同一份 CSS 文件或设计系统文档;组件库升级时,所有引用处都要同步改前缀,而 btn 可以直接 @import 或通过 CDN 加载后开箱即用。真正隔离靠的是 CSS Modules 或 Shadow DOM,不是类名拼凑。
常见错误现象:
- 写成
nc-btn nc-btn--primary,结果在另一个项目里引入同一份按钮 CSS,却因前缀不匹配完全不生效 - 团队 A 的
nc-btn和团队 B 的ds-btn同时加载,但都依赖全局reset.css,导致font-size或line-height冲突
btn 必须脱离上下文独立渲染
它不能靠父容器兜底任何样式。一旦只定义了 color 和 border,却依赖外层提供 font-size 或 display,就会出问题:挪到弹窗里文字变小、嵌入 nav 后变成 inline 元素、在 rem 基准为 10px 的页面中 padding 失控。
必须显式声明以下属性:
-
display: inline-flex(或inline-block) -
padding、font-size、line-height(用无单位值,如1.4,禁用1.4rem) -
cursor、border、vertical-align - 所有尺寸单位统一用
rem,禁用em和px
修饰符叠加必须互不干扰(如 btn--primary btn--disabled)
所有修饰符必须用单类名选择器:.btn--disabled { },不加 .btn 前缀;否则权重不足,btn--disabled 很可能覆盖不了 btn--primary 的背景色或文字色。
关键细节:
-
btn--disabled必须显式重置:pointer-events: none、cursor: not-allowed、opacity(别只改背景色) - 禁止写
.btn--disabled:hover——这会拦截真实 hover 状态,导致禁用按钮意外响应鼠标移入 - 功能型修饰符(如
btn--submit)和状态型修饰符(如btn--loading)必须能自由组合,不能耦合成btn--submit-loading
btn__icon 必须是直系子节点,且布局控制由块级修饰符承担
btn__icon 不是可选装饰,而是按钮功能的一部分;如果 HTML 里写成 <button class="btn">文本</button>,但图标实际藏在 <div> 里,BEM 语义就断裂了。
<p>必须满足:</p>
<ul>
<li>
<code>btn__icon 是 btn 的**直系子节点**,不能隔层
btn--icon-left 这类块级修饰符,而非 btn__icon--left
btn__icon--loading,因为它描述图标自身状态(旋转、占位),不是按钮整体状态最易被忽略的一点:btn 的复用性不取决于命名多“规范”,而取决于它是否真的能在任意 HTML 上下文中插入后立即可用——不靠 JS 注入样式、不靠父容器兜底、不靠开发者临时补 !important。











