drawer--open必须作用于根元素,不能加在子节点上;它表示整个抽屉组件已打开,需绑定到block根节点(如user-action-drawer--open),否则遮罩与面板动画不同步,导致视觉断裂和状态错位。

drawer--open 必须作用于根元素,不能加在子节点上
动画状态类 drawer--open 的语义是「整个抽屉组件已打开」,它必须加在 Block 根节点(如 <div class="user-action-drawer user-action-drawer--open">),否则 CSS 选择器无法联动控制遮罩和内容区域。常见错误是把 <code>drawer--open 加在 drawer__overlay 或 drawer__panel 上——结果遮罩淡入了但面板卡在左侧,或面板滑出了但遮罩仍是全黑,视觉断裂且 JS 状态与 DOM 表现不同步。
drawer__overlay 和 drawer__panel 的动画必须分开声明,且 transition 写在基础类里
drawer__overlay 用 opacity + visibility 实现淡入淡出,drawer__panel 用 transform: translateX(左右方向)或 translateY(上下方向)实现滑入滑出。关键点在于:transition 规则必须写在基础类中,不能只写在修饰符里。否则隐藏时会跳变。
例如:
.user-action-drawer__overlay {
opacity: 0;
visibility: hidden;
transition: opacity 0.25s ease, visibility 0.25s step-end;
}
.user-action-drawer__panel {
transform: translateX(-100%);
transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1);
}
这样当 JS 切换 user-action-drawer--open 时,两个元素才能同步触发入场动画;移除该类时,也能按相同缓动收起。
动画修饰符必须绑定 Block,禁止独立类名如 .fade-in 或 .slide-in
写 .fade-in 这类全局类名会导致样式错位、复用失控、工具链(如 Stylelint、PurgeCSS)识别失败。BEM 要求所有动画状态都用 -- 修饰符,并严格绑定到 Block,比如 user-action-drawer--fading 或 user-action-drawer--sliding-in。
多个动画状态应平级共存,而非嵌套:
- ✅ 正确:
user-action-drawer--open user-action-drawer--fading - ❌ 错误:
user-action-drawer--open-fading或user-action-drawer--open user-action-drawer--fading user-action-drawer--zoom(若未定义 --zoom 规则,则无效)
JS 控制时需确保事件时机:添加 --sliding-in 后监听 transitionend,再移除旧状态类;频繁切换前调用 el.getAnimations().forEach(a => a.cancel()) 防止竞态。
z-index 和 fixed 定位必须配合自定义属性,否则遮罩会被其他浮层盖住
drawer__overlay 必须用 position: fixed + inset: 0,绝不能依赖父容器定位,也绝不能被包裹在带 transform、opacity 或 <code>will-change 的祖先里——否则会创建新层叠上下文,导致 z-index 失效。
层级必须用 CSS 自定义属性统一管理:
:root {
--z-drawer: 1100;
}
.user-action-drawer {
z-index: var(--z-drawer);
}
.user-action-drawer__overlay {
z-index: calc(var(--z-drawer) - 1);
}
否则容易出现抽屉被下拉菜单(z-index: 1050)盖住,或遮罩压不住通知框(z-index: 800)的情况。这个细节在多组件共存的项目里几乎必踩。











