bem 修饰符必须用双连字符--紧贴块名命名,如.modal--open;禁止单横线、驼峰或无上下文写法;transition/animation需显式声明;多状态须平级共存;js需匹配动画生命周期事件。

动画修饰符必须用--开头并绑定到具体 Block
直接写.fade-in或.is-open不是 BEM 修饰符,工具链(Stylelint、PostCSS 插件)识别不了,IDE 类名跳转失效,CSS 权重也压不过.modal__content这类元素选择器。真正有效的命名是.modal--open、.card--fade-in——双连字符--是解析器唯一认可的状态标识,且必须紧贴块名,不能断开。
常见错误包括:.modal-fade-in(单横线被当新 Block)、.modalFadeIn(驼峰不合法)、.is-fading(无上下文,非 BEM 修饰符)。这些写法会让样式无法精准锚定到组件,JS 添加类后也找不到对应规则。
transition和animation必须显式声明在对应选择器中
只加.button--hovered类,但 CSS 里没写transition: transform 0.2s ease,或者漏了transition-property,动画就完全不触发。浏览器不会继承父级的transition,也不会自动补全属性。
- 用
transition:基础类(如.drawer)必须先定义transition: max-height 0.3s ease,修饰符(如.drawer--expanded)只负责改值(max-height: 500px) - 用
animation:修饰符规则里必须完整写出animation: card-fade-in 0.4s ease,不能只靠@keyframes存在就生效 - 禁用
* { transition: all .2s }:它会让margin、color等非预期属性也过渡,且阻断will-change优化
多个状态需平级共存,禁止嵌套修饰符
BEM 不允许.modal--fade-in--scale或.card--loading--disabled这种链式写法。它们不是父子关系,而是并列布尔开关,应独立添加、分别控制。
正确做法是:class="modal modal--fade-in modal--scale",并在 CSS 中分别定义两个修饰符的效果:
.modal--fade-in .modal__overlay { animation: modal-fade-in 0.25s ease; }
.modal--scale .modal__content { transform: scale(1.02); }
JS 控制时也应分开操作:el.classList.toggle('modal--fade-in') 和 el.classList.toggle('modal--scale'),避免耦合。
JS 控制类名必须匹配动画生命周期事件
类名加完立刻移除,动画根本播不完;监听animationend却不检查event.animationName,可能误删其他动画的类。关键不是“怎么加”,而是“什么时候加、什么时候收”。
- 入场动画:
el.classList.add('card--fade-in')→ 监听animationend→ 检查event.animationName === 'card-fade-in'→ 再清理 - 退出动画:先加
card--fade-out,再移除card--fade-in,确保退出过渡能被触发 - 竞态处理:同一元素频繁切换时,先调用
el.getAnimations().forEach(a => a.cancel())中断旧动画
最易被忽略的是:修饰符语义必须和组件强绑定。.card--fade-in挪到.modal上就失效;硬件加速是否启用、animationend事件过滤是否严格,全都依赖这个绑定成立。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











