BEM规范禁止直接使用.card:hover,因其将交互状态耦合进样式层,破坏类名语义明确性;应改用--is-hovered修饰符配合JS控制,并通过媒体查询或JS环境检测实现触屏降级。

为什么直接套用 .card:hover 会破坏BEM结构
BEM要求每个类名必须明确表达“它是什么”,而不是“它在什么状态下”。.card:hover 是伪类选择器,不生成新类名,本质上把状态逻辑塞进了样式层,导致:组件复用时无法单独控制悬停样式;想在JS里动态切换悬停态(比如触屏模拟)根本无从下手;多人协作时,有人写 .card--hovered,有人写 .card.is-hovered,命名立刻失控。
hover 状态该用哪种BEM修饰符: --hovered 还是 --is-hovered
用 --is-hovered。理由很实际:--hovered 容易被误解为“已执行悬停动作”,而 --is-hovered 明确表示“当前处于悬停状态”,和 --is-active、--is-open 保持语义一致。更重要的是,它能被JS干净地增删:
element.classList.toggle('card__body--is-hovered');别碰 :hover 本身——它只负责触发,不负责定义样式。所有视觉变化都应通过 --is-hovered 类来实现。
悬停卡片里的子元素怎么命名才不越界
卡片内部的图标、标题、按钮,必须严格遵循 BEM 的“块内独立”原则。常见错误是写成 .card__icon:hover 或 .card__title--hovered。正确做法是:
立即学习“前端免费学习笔记(深入)”;
- 子元素状态由父块统一控制:卡片悬停时,给整个
.card加--is-hovered,再用.card--is-hovered .card__icon去改图标颜色 - 子元素自身若有独立交互(比如图标可点击),它自己得有一套完整BEM,比如
icon--is-clickable,和卡片的悬停状态解耦 - 禁止跨块写样式,如
.card--is-hovered .button—— 按钮必须声明自己的块名.button,否则一换主题就全崩
触屏设备下 --is-hovered 怎么安全降级
纯CSS的 :hover 在iOS Safari和安卓Chrome里行为不一致,尤其在“轻点即跳转”的页面上,--is-hovered 可能一闪而过。解决方案不是删掉它,而是加一层媒体查询兜底:
@media (hover: hover) and (pointer: fine) {
.card:hover {
/* 只在此类设备上自动加 --is-hovered */
}
}更稳妥的做法是:JS检测 matchMedia('(hover: hover)'),只在支持悬停的设备上绑定 mouseenter/mouseleave,其他设备完全忽略 --is-hovered 类。这点容易被忽略——很多人写了BEM却没管运行时环境适配。


















