nav和dropdown必须是两个独立block:nav仅负责语义与布局(nav__list、nav__item),dropdown自主封装交互逻辑(dropdown__toggle、dropdown__menu);所有下拉DOM须包裹在dropdown容器内,禁止跨块嵌套或散落于nav__item中。

下拉菜单用 BEM 写不维护,根本不是类名拼得不够长,而是把 dropdown 塞进 nav 里当子元素硬套命名——这直接破坏职责边界,后续加个 hover 动效或换触发方式就得重测整个导航结构。
为什么不能写 nav__dropdown 或 nav__submenu
这类命名看似省事,实则把交互逻辑(显隐、定位、过渡)强行寄生在布局块上。BEM 不是字符串拼接游戏,nav 只该管语义和布局(nav__list、nav__item、nav__link),而 dropdown 必须是完整、可独立复用的 block。
-
nav__item内部只放一个<div class="dropdown"></div>,不写任何dropdown__相关样式规则 - 所有下拉 DOM(
dropdown__toggle、dropdown__menu)必须包裹在dropdown容器内,禁止散落在nav__item的子节点中 - 二级菜单不是 “子项”,而是另一个
dropdown实例,直接放在上层dropdown__menu里
dropdown__toggle:hover + .dropdown__menu 失效的真正原因
90% 的 hover 闪退不是 CSS 写错了,是 DOM 断链了。这个选择器要求两个元素必须是紧邻兄弟节点,而框架(Vue 的 <transition>、React 的 <Fragment>)或手写 wrapper 很容易插在中间。
- 检查 HTML 是否满足任一结构:
<button class="dropdown__toggle"></button><div class="dropdown__menu"></div>(相邻兄弟);或<div class="dropdown"><button class="dropdown__toggle"></button><div class="dropdown__menu"></div></div>(同父包裹) - 若必须用
:has()(如.dropdown:has(.dropdown__toggle:focus-within) .dropdown__menu),注意 Safari 15.4+/Chrome 105+ 才稳定 - 补救措施:给
dropdown__menu加min-width: max-content防内容收缩后鼠标移出热区;加transition-delay: 0.1s缓解视觉断连 - JS 控制显隐时,用
display: none或visibility: hidden,别用remove()
多级菜单命名爆炸怎么破
出现 nav__item__submenu__link 这种类名,说明结构已经失焦。BEM 不允许跨 block 嵌套命名,“三级”不是层级深度,而是多个 dropdown 实例按需嵌套的结果。
立即学习“前端免费学习笔记(深入)”;
- 每一层下拉都是可独立测试、可配置触发方式、可替换动效的
dropdown,不是“子元素” - 差异靠修饰符解决:
dropdown--mega、dropdown--click、dropdown--mobile,而非堆砌层级 - 共享基础样式(
dropdown),差异走修饰符,比为每级写专属类名更易缓存、更少 CSS 规则膨胀
最常被忽略的一点:DOM 结构是否真的紧邻或包裹,比 CSS 写得多漂亮都重要。hover 失效、状态错乱、样式污染,八成起源于这一层没对齐。


















