可复用单元必须定义为独立 block,而非父容器下的 element;block 应自包含样式、状态、交互逻辑,支持脱离上下文直接渲染;命名与结构须按功能而非位置划分,避免跨块复用和越界访问。

每个可复用单元必须是独立 block
树节点、面包屑项、图注这些视觉模块,只要可能被单独渲染或复用,就必须定义为独立 block,而不是某个父容器下的 __element。比如写一个树形控件,不能只建一个 tree 块然后塞满 tree__node、tree__node__icon —— 这会让子节点样式强依赖父级结构,一旦挪到别处就失效。
真实项目里最常出问题的是:把 person-card__avatar 当作元素写,结果发现它在用户列表页和详情页表现不一致,因为它的圆角、尺寸、加载状态逻辑全耦合在 person-card 里。正确做法是把它升格为 avatar 块,自己管缩放、状态、占位图,person-card 只负责布局位置和上下文语义(如 person-card--compact)。
- 判断标准:这个模块能否脱离当前页面/组件,在另一个 DOM 上下文中直接
innerHTML渲染并正常工作?能 → 它该是 block - JS 初始化也应按 block 切分:
new Avatar(document.querySelector('.avatar')),而不是initPersonCardAvatars() - 避免“伪 block”:像
layout__sidebar这种命名本质是位置描述,不是功能,容易随 UI 调整而失效
缩进、状态、图标等视觉表现必须封装在 block 内部
缩进不是靠 tree-node--level-2 这类类名硬编码层级,而是由 JS 渲染时注入 data-level="2",CSS 用属性选择器控制:[data-level="2"] { padding-left: 2em; }。这样树深度变化时,HTML 和 CSS 都不用改。
同理,图标状态不靠 tree-node__icon--expanded 和 tree-node__icon--collapsed 切换,而是统一用 tree-node__icon,再通过 tree-node--is-expanded .tree-node__icon 控制旋转或切换 SVG use 引用。状态修饰符挂载在 block 上,而非分散到每个子元素。
- 禁止用
__element--modifier表达跨元素共用状态,例如“加载中”应该用form--is-loading,而不是form__input--loading+form__submit--loading - 图标建议用
,状态变更只需切href或加 class 控制 fill/stroke - 所有内边距、对齐、尺寸控制都应在 block 级完成,
__element只负责内容容器职责,不参与布局计算
BEM 类名过长?说明组件边界没划清
user-profile-card__header-avatar-wrapper--is-loading 这种类名不是 BEM 本身的问题,是把本该独立的 avatar、loading-spinner、profile-header 全揉在一个 block 里导致的。BEM 不反对长名,但反对无意义的嵌套。
解决方式很简单:把高频复用、有独立交互或状态的子结构,直接拆成新 block。比如搜索表单里的输入框和按钮,原本写成 search-form__input-field 和 search-form__submit-button,现在改为 form-field 和 button 两个独立块,search-form 只保留布局容器角色(如 search-form--inline)。
- 命名优先功能而非位置:
price-tag✔️,product-card__price-tag❌ - 文件夹结构要同步调整:/components/price-tag/ 下放完整样式、JS、测试,不塞进 /components/product-card/
- 纯布局辅助类(如
grid-col-4)可例外,但仅限无业务语义的栅格工具
多层嵌套时,block 之间不能越界访问 element
图文详情页里一张图的图注,必须是 article-content__caption,不能在 product-detail-layout__main 区域里误用 gallery-item__caption。这两个 block 完全无关,跨块复用 element 类名会导致样式污染、JS 查询失败、维护时不敢动。
更隐蔽的问题是:当某个 block 内部需要嵌套另一个 block 时,DOM 结构上可以嵌套,但 CSS 作用域必须隔离。比如 breadcrumb 块里放了一个 link 块,link 的样式不能靠 .breadcrumb .link 来覆盖,而应让 link 自身支持 link--in-breadcrumb 这类上下文修饰符,或通过 CSS :where() 降低特异性干扰。
- JavaScript 查找元素必须严格按 block 边界:
el.querySelector('.article-content__caption')不应出现在 product-detail 页面的脚本里 - Less/Sass 中慎用
&拼接多层上下文,如.product-detail-layout { &__main { .article-content__caption { ... } } }—— 这等于手动制造耦合 - 真正难的不是写对类名,而是敢把一个“看起来很像子元素”的东西,单独拎出来当成 block 维护,哪怕它目前只在一处用到
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











