bem禁止使用div.card等标签选择器,因其破坏样式作用域隔离——bem依赖类名自身表达边界,混入标签名会使样式强耦合dom结构,一旦html结构调整(如换用),样式立即失效。

为什么BEM禁止使用div.card这类标签选择器
BEM 的样式作用域完全靠类名自身表达边界,一旦混入div.card这种写法,就等于主动放弃隔离能力——浏览器会把div当作必要条件,哪怕你把.card换成<section></section>或<article></article>,样式立刻失效。
常见错误现象:.header__nav ul li a被重写成.header__nav .header__nav-item,表面加了 BEM 前缀,实际仍依赖 DOM 层级;后续换用 Flexbox 替代ul/li时,整套导航样式得重写。
- 所有 BEM 规则必须只基于类名:
.card、.card__title、.card--loading - 禁止任何标签名、伪类、属性选择器参与核心样式定义
- 若真需区分容器语义(比如
<header></header>和<section></section>下的card行为不同),应通过顶层 class 控制:.layout-header .card或[data-layout="header"] .card,而非硬绑标签
.card__title:hover和.card__title--hover哪个更符合BEM
.card__title:hover是合法且推荐的写法;.card__title--hover是典型误用。
BEM 的--修饰符只描述静态可复用的状态或变体,比如--disabled、--compact,而:hover是用户交互触发的临时视觉反馈,不属于组件固有状态。
- 混淆这两者会导致:同一修饰符在不同上下文要重复定义 hover 样式(如
.btn--primary:hover和.link--primary:hover),违反 DRY - 更严重的是,当 JS 主动添加
--hover类模拟悬停效果时,会和真实伪类冲突,调试时根本分不清是哪段逻辑生效 - 基础交互统一由基础类接管:
.card__title:hover { color: #007bff; },不带 Block 前缀也行,只要它不污染全局 - 仅当某修饰符需要覆盖默认交互行为时,才显式写
.card__title--disabled:hover { cursor: not-allowed; }
第三方组件嵌入时,标签选择器是不是唯一出路
不是。给 Ant Design 的<button></button>塞进profile-card里,别试图给它加profile-card__button类,也别写.profile-card .ant-btn——后者会随库升级失效,前者破坏其内部状态类(如.ant-btn-disabled)。
- 正确做法是用 wrapper block 包一层,比如
.form-field--date,再通过属性选择器或:global(如用 CSS Modules)局部覆盖 - 避免在第三方组件上直接写
button.ant-btn或div.ant-modal,这类选择器权重高、耦合深、维护成本爆炸 - 工具链中启用
stylelint-selector-bem-pattern并配置componentName: "^[a-z][a-z0-9-]*$",可拦截div.card类写法
BEM选择器嵌套层级超过2层意味着什么
意味着你正在用 CSS 层级关系替代命名表达,这违背 BEM “用名字本身表达结构”的初衷。
常见错误:.modal .content .title这种写法,结果父组件里另一个.content被意外染上样式;或者 Sass 中写.card { &__title { &__icon {} } },生成.card__title__icon——BEM 明确禁止 Element 嵌套。
-
.block__element--modifier算 1 层;.block .block__element才算嵌套(已违规) - SCSS 中只允许单层嵌套:
.card { &__title {} &__content {} },禁止出现&__title &__icon(空格会生成后代选择器) - 性能影响几乎为零,但深层嵌套会让调试变得不可预测:你改
.card时,永远不确定是否悄悄影响了某个.card .item .link
div.card那一行埋下了。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











