导航栏与下拉菜单必须拆分为独立block:nav负责结构布局(nav__list、nav__item),dropdown负责交互逻辑(dropdown__toggle、dropdown__menu),二者dom需紧邻或直接父子,禁止nav__dropdown等跨块命名。

导航栏用 BEM 命名,关键不是“怎么写类名”,而是“哪些该拆成独立 block”。把 dropdown 塞进 nav__item 里硬套命名,90% 的 hover 闪退、状态失效、样式污染都源于此。
nav 和 dropdown 必须是两个独立 block
很多人写 nav__dropdown 或 nav__submenu,这违背 BEM 的职责划分。nav 只管语义结构和布局(nav__list、nav__item、nav__link),而下拉交互逻辑(触发、面板定位、显隐过渡)属于 dropdown 自身的职责。
-
dropdown必须是完整、可复用的 block:包含dropdown__toggle和dropdown__menu,且二者在 DOM 中必须是相邻兄弟或直接父子关系 -
nav__item内部只负责容纳一个dropdown实例,不掺杂任何dropdown__相关样式规则 - 多级菜单时,子级下拉仍是独立
dropdown,不是nav__item__dropdown或dropdown__menu__submenu——BEM 不允许跨 block 嵌套命名
.dropdown__toggle:hover + .dropdown__menu 失效怎么办
hover 闪退根本不是 CSS 写错了,是 DOM 断链了。浏览器中该选择器失效,几乎全是 HTML 结构问题:
- Vue 的
<transition></transition>、React 的<fragment></fragment>、或手写的包装<div class="wrapper"> 插在中间,导致兄弟选择器断开 <li>确保 <code>dropdown__toggle和dropdown__menu在 DOM 中紧邻,或dropdown__menu是dropdown__toggle的直接父/子节点(若用:has()需注意兼容性) - 给
dropdown__menu加min-width: max-content,防止内容收缩后鼠标移出热区 - 加
transition-delay: 0.1s到dropdown__menu的opacity或transform上,缓解视觉断连感 - JS 控制显隐时,用
display: none或visibility: hidden切换,别用remove()——否则 BEM 类还在,但结构已断裂 -
nav.css:只含nav、nav__list、nav__item等容器与布局规则,不含皮肤层(颜色、字体)或交互层(hover、z-index) -
nav-dropdown.css:仅当项目用到下拉时才引入,只定义dropdown块及其过渡、定位、z-index -
_nav-theme.css:抽成 CSS 自定义属性(--nav-bg、--nav-link-color),换肤不改结构 - 媒体查询统一交给
layout-responsive.css管理,否则响应式逻辑会和nav职责耦合
nav.css 里不该塞什么
CSS 文件按职责拆,不是按“看起来像一块”。模块化不是起个好名字就完事,关键是文件组织让人一眼看出“这个样式管哪块、能不能单独抽走”。
真正容易被忽略的是:BEM 的结构假设一旦被框架抽象层(比如 React 的 Fragment、Vue 的 teleport)悄悄打破,CSS 就会立刻失能——它不报错,只是“不生效”,排查时却总往样式权重或伪类上想。所以每次加交互组件前,先检查 DOM 树里那两个关键节点是不是真的挨着。











