动画类名必须是--开头的修饰符并绑定到具体Block根节点,如.modal--fade-in;.fade-in为全局类易错位覆盖,.modal-fade-in被解析为新Block导致工具链失效、选择器权重不足,且修饰符须显式声明animation/transition并严格匹配@keyframes名称。

动画类名必须是 -- 开头的修饰符,且必须绑定到具体 Block 根节点,否则 CSS 不生效、JS 控制失锚、工具链(Stylelint / PostCSS)无法识别。
为什么 .modal--fade-in 不能写成 .fade-in 或 .modal-fade-in
浏览器不解析语义,只认选择器字面匹配;.fade-in 是全局类,加在 .card 上会覆盖错样式,加在 .toast 上又缺位移起点。.modal-fade-in 被 BEM 工具链当成新 Block,IDE 类名跳转失效,CSS 权重也低于 .modal__content,极易被覆盖。
-
.modal--fade-in✅ 明确表达“modal 这个块正处于淡入状态” -
.modal-fade-in❌ 解析为独立 Block,脱离上下文 -
.is-fading❌ 不是 BEM 修饰符,工具不识别,开发者难定位来源
.modal--fading-out 必须显式声明 animation 或 transition
只加 class 不写动画属性,等于没写。BEM 不自动注入行为,修饰符本身不带样式逻辑。
- 用
animation(如入场/循环):修饰符规则里必须完整写animation: fade-in 0.4s ease,且@keyframes fade-in名称要严格对齐 - 用
transition(如 hover 缩放):基础类.modal必须先声明transition: transform 0.2s ease,修饰符只负责改值(如transform: translateY(0)) - 禁用
* { transition: all .2s }:它会让margin、color等非预期属性也过渡,且阻断will-change优化
JS 控制动画类名时,时机比增删逻辑更重要
类名加完立刻移除,动画根本播不完;监听 animationend 却不校验 event.animationName,可能误删其他动画的类。
立即学习“前端免费学习笔记(深入)”;
- 入场动画:
el.classList.add('modal--fade-in')→ 监听animationend→ 检查event.animationName === 'fade-in'→ 再清理 - 退出动画:先
add('modal--fade-out'),再remove('modal--fade-in'),确保 CSS 能触发退出过渡 - 竞态处理:同一元素频繁切换时,先调用
el.getAnimations().forEach(a => a.cancel())主动中断旧动画
最易被忽略的是修饰符和组件的强绑定关系——.card--fade-in 挪到 .modal 上就失效;硬件加速条件(是否用 transform)、事件过滤、取消逻辑,全都依赖这个绑定成立。


















