状态类名必须以 is- 开头(如 is-sidebar-open),仅由 js 添加/移除,css 仅定义其视觉效果;transition 必须写在基础类 .sidebar 上;响应式逻辑应由布局层(如 .layout)控制,而非元素修饰符。

侧边栏状态类名必须带 JavaScript 控制标识
直接用 .sidebar--open 或 .sidebar--closed 做 CSS 切换,但不加 JS 可控前缀,会导致样式被静态渲染“锁死”,服务端渲染或初始 HTML 里写错就无法动态修正。BEM 的修饰符(modifier)本身不携带行为语义,得靠 JS 显式增删才能可靠响应交互。
正确做法是:状态类名统一以 is- 开头,比如 is-sidebar-open,并确保它只由 JS 添加/移除——CSS 里只定义这个类的视觉效果,不依赖其他上下文:
.sidebar {
transition: width 0.3s ease;
width: 260px;
}
.is-sidebar-open .sidebar {
width: 260px;
}
.is-sidebar-closed .sidebar {
width: 60px;
}
-
is-前缀是 BEM 社区广泛接受的状态命名约定,明确表示“当前处于某种运行时状态” - 不要用
.sidebar--open直接控制宽度,否则 JS 未加载时页面可能显示异常宽度 - 父容器加状态类(如
),比操作侧边栏自身更利于样式隔离和嵌套控制
响应式断点与 BEM 元素层级需解耦
很多人把媒体查询硬塞进 .sidebar__trigger--mobile 这类修饰符里,结果在桌面端也加载了移动端触发器的样式逻辑,造成冗余甚至冲突。BEM 的元素(element)应保持功能内聚,响应式适配该由容器或布局层接管。
推荐结构:
<div class="layout"> <aside class="sidebar">...</aside><main class="layout__content">...</main> </div>
- 所有响应式规则写在
.layout或body上,例如:@media (max-width: 768px) { .layout.is-sidebar-closed .sidebar { display: none; } } -
.sidebar__trigger只负责点击区域样式,是否显示由.layout的断点类控制 - 避免在
.sidebar__item--active里写display: none,那属于布局职责,不是列表项自己的状态
transition 动画必须绑定到基础类,而非状态修饰符
如果只在 .is-sidebar-open .sidebar 里写 transition: width 0.3s,那么收起时动画会失效——因为 .is-sidebar-closed 下没定义 transition,浏览器会跳变回默认宽度。
- 动画属性必须声明在非状态的基础选择器上,即
.sidebar自身要带transition - width、transform、opacity 等可动画属性,只要值变化,就得靠基础类兜底过渡行为
- 慎用
height: auto配合 transition,它不会动画;改用max-height或transform: scaleY()更可靠
JavaScript 控制状态时,避免直接操作 style 属性
用 element.style.width = '60px' 会覆盖 CSS 中的 transition 和媒体查询,且破坏 BEM 的样式管理边界。JS 应只负责状态标记,样式逻辑全留在 CSS 里。
- 切换状态统一用
document.body.classList.toggle('is-sidebar-closed') - 监听 resize 时,不要重新计算宽度赋给 style,而是切换断点类,例如:
document.body.classList.toggle('is-mobile-layout', window.innerWidth - 需要记忆用户偏好时,把状态存 localStorage,但读取后仍通过 classList 操作 DOM,不绕过 CSS
最易被忽略的是:移动端触摸事件触发后,若未阻止默认行为或未处理点击穿透,可能导致快速连点两次,is-sidebar-open 和 is-sidebar-closed 被连续添加又删除,视觉卡顿。加个简单节流或用 pointer-events: none 临时禁用触发器更稳妥。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











