nav 和 dropdown 必须是独立 block,nav 仅负责语义结构与布局,dropdown 自主管理触发、定位、显隐及动效;所有下拉 DOM 必须包裹在 dropdown 容器内,禁止散落或跨块嵌套,状态类应作用于 dropdown 根元素。

nav 和 dropdown 必须是两个独立 block
强行把下拉菜单塞进 nav__item__dropdown 或 nav__submenu 会导致样式耦合、状态难维护、动效改一处全链路重测。BEM 不是拼接字符串的游戏,而是职责划分的契约: nav 只管语义结构与布局(nav__list、nav__item、nav__link),所有触发、面板定位、显隐过渡逻辑必须由 dropdown 自己承担。
常见错误现象:nav__item 里直接写 dropdown__menu 样式规则;二级菜单加个 --slide 动效,结果类名变成 nav__item__dropdown--slide —— 这等于把交互逻辑寄生在布局块上。
-
nav__item内部只放一个,不写任何dropdown__相关样式 - 所有下拉 DOM(
dropdown__toggle、dropdown__menu)必须包裹在dropdown容器内,不能散落在nav__item的子节点中 - 多级嵌套时,子级下拉仍是独立
dropdown实例,不是dropdown__menu__submenu
dropdown__toggle 和 dropdown__menu 的 DOM 关系必须对齐 CSS 假设
.dropdown__toggle:hover + .dropdown__menu 失效?90% 是因为中间插了无关节点。BEM 的兄弟选择器或 :has() 行为依赖严格的 DOM 邻接关系,而框架(Vue 、React Fragment)或手写 wrapper 很容易破坏它。
使用场景:纯 CSS hover 显隐、:focus-within 移动端适配、JS 控制显隐时保留热区连续性。
- 推荐 HTML 结构:
(紧邻兄弟) - 若框架强制插入 wrapper,改用
.dropdown:hover .dropdown__menu,但需确保.dropdown有position: relative - 给
.dropdown__menu加min-width: max-content,防止内容收缩后鼠标移出热区导致闪退 - 避免 JS 直接
remove()dropdown__menu,用display: none或visibility: hidden切换更安全
多级菜单不是“三级元素”,而是递归复用的 dropdown 实例
写到 nav__item__submenu__link 就该警觉:这不是层级深,是结构失焦。BEM 不靠类名深度表达嵌套,而靠 DOM 层级 + 独立 block 复用实现递归。每一层下拉都是可独立测试、可配置触发方式、可替换动效的 dropdown。
性能影响:共享基础样式(dropdown)、差异走修饰符(dropdown--mega、dropdown--inline),比为每级写专属类名更易缓存、更少 CSS 规则膨胀。
- 一级菜单:
- 二级菜单:在上层
dropdown__menu中再嵌一个,不是dropdown__submenu - 修饰符用于变体,如
dropdown--hover/dropdown--click,而非nav__dropdown--level-2 - 图标、文字、分隔线等视觉元素,若与 item 强耦合(如 hover 同步变色),统一用
nav__item--hover控制,不拆成nav__item-icon单独样式
状态类必须挂载在宿主元素上,不能跨块传递
nav__item--active 合理,dropdown__menu--open 错误——打开状态属于 dropdown 整体,应写成 dropdown--open。修饰符只能修饰它所属的 block 或 element,跨块命名(如 nav__item__dropdown--open)会污染命名空间,且无法复用。
容易踩的坑:用 JS 切换状态时,把 class 加在错误层级;CSS 权重因跨块修饰符堆叠而失控;主题切换时无法批量控制 dropdown 行为。
- 激活态、焦点态、加载态等,都作用于
dropdown根元素,如dropdown--open、dropdown--loading -
dropdown__option类只承载静态属性(dropdown__option--disabled),不负责“当前选中”逻辑;选中态由dropdown--has-selection统一控制 - 禁止出现
nav__dropdown--open、dropdown__menu--visible、nav__item__dropdown--active
复杂点不在怎么命名,而在是否愿意把交互边界当真——只要 dropdown 还被当作 nav 的附属品,类名再长也救不了结构。











