bem 不允许跨 block 命名,nav__item__submenu 错误因 submenu 实为独立 dropdown block;应封装为完整 dropdown,用修饰符(如 dropdown--mega)区分形态,dom 须保持 toggle/menu 相邻或同父结构,js 显隐须用 css 状态控制而非 dom 移除。

为什么 nav__item__submenu 这类命名一写就出问题
因为 BEM 不允许跨 block 命名,“submenu”不是 nav 的子元素,而是另一个独立的 dropdown 实例。写成 nav__item__submenu 直接把交互逻辑(显隐、定位、过渡)强行寄生在布局块上,后续改个 hover 动效或换 click 触发,整个导航结构都得重测。
正确做法是:每个下拉菜单都封装为完整 dropdown block,nav__item 里只放一个 <div class="dropdown"></div>,不掺任何 dropdown__ 样式规则。
-
nav__item只负责语义与布局:间距、对齐、基础 hover 色彩 -
dropdown自主管理 toggle、menu、定位、动画,可单独复用、测试、配置 - 二级菜单不是“子项”,而是在上层
dropdown__menu内部再嵌一个<div class="dropdown"></div>
多级嵌套时 DOM 结构怎么写才不破坏 .dropdown__toggle:hover + .dropdown__menu
这个选择器失效,90% 是 DOM 断链——Vue 的 <transition></transition>、React 的 <fragment></fragment> 或手写的 wrapper 都可能插在中间,导致兄弟关系断裂。
必须确保以下任一结构成立:
-
<button class="dropdown__toggle"></button><div class="dropdown__menu"></div>(相邻兄弟) -
<div class="dropdown"> <button class="dropdown__toggle"></button><div class="dropdown__menu"></div> </div>(同父包裹) -
<div class="dropdown"><div class="dropdown__menu"><button class="dropdown__toggle"></button></div></div>(直接父子,需配合:has(),注意 Safari 15.4+ / Chrome 105+ 才稳定)
补救措施:dropdown__menu 加 min-width: max-content 防内容收缩后鼠标移出热区;加 transition-delay: 0.1s 缓解视觉断连。
如何避免写到三级就开始命名爆炸
出现 nav__item__submenu__link 或 dropdown__menu__submenu__item,说明结构已经失焦。“三级”根本不是层级深度,而是多个 dropdown 实例按需嵌套的结果。
差异靠修饰符解决,而不是靠父级前缀模拟层级:
-
dropdown--mega(宽幅面板) -
dropdown--click(非 hover 触发) -
dropdown--mobile(移动端适配)
所有实例共享基础样式 dropdown,修饰符只覆盖必要差异。这样 CSS 规则更少、缓存更高效,也避免改一个动效要全局搜索替换。
JS 控制多级显隐时最容易忽略的细节
用 JS 切换状态时,最常踩的坑是调用 remove() 或清空 innerHTML —— 这会让 DOM 结构断裂,BEM 类还在但对应节点已消失,CSS 选择器彻底失效。
正确方式是用 CSS 控制显隐状态:
- 用
display: none/display: block切换(适合简单场景) - 用
visibility: hidden/visibility: visible+opacity(保留占位,支持过渡) - 避免依赖
max-height: 0 → max-height: auto,auto 不可插值,动画会失效;改用预估固定值,如max-height: 400px
真正难的不是写多少类名,而是让每个 dropdown 在任意嵌套深度下,仍能独立响应、独立配置、独立销毁而不污染父级。这需要从第一层 HTML 就切断跨块耦合。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











