伪类必须直接作用于Block或Element类名,不可挂在Modifier上;伪元素归属取决于其视觉功能归属,组合顺序为“类名→伪类→伪元素”,且需避免跨Block组合与动态content陷阱。

伪类(:hover、:focus等)该挂在哪一级类名上
伪类必须直接作用于 Block 或 Element 类名,不能挂在 Modifier 上——因为 Modifier 本身只是状态标识,不承担交互逻辑。比如 .button--primary:hover 是错的,它把视觉状态(--primary)和交互行为(:hover)耦合了;正确写法是 .button:hover 或 .button__text:focus。
常见错误现象:鼠标悬停时只有 primary 按钮变色,secondary 按钮无反馈,导致交互不一致;根源是把伪类绑在修饰符上,漏写了基础 Block 的 hover 样式。
- 所有可交互的 Block 都应定义基础伪类,如
.button:hover、.input:focus - Element 级伪类仅用于局部响应,如
.card__close:hover,但前提是card__close是独立可交互单元 - 避免写
.button--disabled:hover—— disabled 状态下本就不该响应 hover,CSS 会忽略,但语义混乱
::before 和 ::after 应该用 Block 还是 Element 命名
伪元素的类名归属取决于它“属于谁”。如果 ::before 是 Block 的视觉组成部分(如按钮左侧图标、卡片角标),就用 Block 名派生:.tag::before;如果是某个 Element 的装饰(如输入框右侧清空按钮的叉号),就用 Element 名:.search-form__clear::before。
容易踩的坑是硬套结构:看到 card__header 里加了 ::before,就写成 .card__header::before,结果这个装饰其实复用于所有 header 场景,本质是独立 Block(比如 .badge),不该依附于 card。
立即学习“前端免费学习笔记(深入)”;
- 伪元素不生成 DOM 节点,但它承载的视觉功能必须有明确归属——是 Block 的一部分?还是 Element 的附属?
- 不要用
.block__elem::before去模拟一个本该是独立 Block 的组件(如带圆点的 status indicator) - 若伪元素需动态控制显隐或样式,优先通过 Modifier 控制,如
.badge--online::before,而非 JS 操作style.content
BEM 下如何安全地组合伪类与伪元素
组合顺序必须是「类名 → 伪类 → 伪元素」,且中间不能插入后代选择器。正确写法:.button:hover::before;错误写法:.button:hover .button__icon::before(用了空格,破坏 BEM 隔离性)或 .button::before:hover(语法非法)。
这种组合在真实项目中常用于加载态按钮、带图标的状态标签、悬停展开的菜单箭头等场景。性能影响极小,但兼容性要注意:IE11 不支持 ::before:hover 这种链式写法,需降级为单独声明 .button:hover::before。
- SCSS 中推荐用
&:hover::before,确保生成的选择器严格对应 Block 或 Element - 避免跨 Block 组合,如
.card:hover .card__title::before—— 这等于在暗示card__title的样式依赖card的 hover 状态,违背 BEM 的无上下文依赖原则 - Modifier 可参与组合,但仅限语义合理时,如
.button--loading::before表示加载动画,而不是.button--loading:hover::before
React/Vue 中动态插入伪元素内容的陷阱
伪元素的 content 属性无法通过 React 的 className 动态控制,也不能用 style={{ content: '...' }}(无效)。真正可控的方式只有两类:一是用 Modifier 切换预设值,如 .status--success::before { content: "✓" };二是用属性选择器,如 [data-status="error"]::before { content: "×" },再由组件传入 data-status。
最常被忽略的点:开发者试图用 useEffect 动态修改 <style> 标签或注入新 CSS 规则,这不仅破坏 SSR 一致性,还会造成样式泄漏和内存泄漏。
- 纯视觉符号(✓、×、»)全部走 Modifier + 预设
content - 需要显示文本内容的伪元素(如 tooltip 提示),改用真实 DOM 节点,伪元素只负责三角箭头等装饰部分
- 不要在 styled-components 或 emotion 中用插值拼接
content,它会被转义或忽略
::before 该叫 .card__header::before 还是 .badge::before,说明你已经在思考组件边界了,这才是 BEM 真正起作用的地方。


















