多级下拉菜单应使用独立的 dropdown block 而非嵌套命名,如 nav__item__submenu;每层均为可复用、可独立测试的 block,通过 modifier(如 dropdown--nested)和 DOM 层级控制样式与行为。

多级下拉菜单不该用 nav__item__submenu 这类嵌套命名
这种写法看似“表达了层级”,实则破坏 BEM 的模块边界。nav__item__submenu 暗示 submenu 是 nav__item 的子元素,但语义上它是个可独立显隐、带定位逻辑、甚至可能复用到侧边栏的交互单元。一旦你给二级菜单加个 dropdown--slide 动效,就不得不写成 nav__item__submenu--slide——这等于把 dropdown 的行为逻辑硬塞进 nav 的命名空间里。
真正该做的,是承认:每一层下拉都是一个独立 dropdown block。一级菜单项里放一个 dropdown,它的面板里某个 dropdown__item 又可以再放一个 dropdown 实例。BEM 不靠类名深度表达嵌套,而靠 DOM 层级 + 独立 block 复用实现递归。
- 禁止出现
nav__item__dropdown、dropdown__menu__submenu、nav__dropdown--level-2 - 允许且推荐:
在任意位置重复使用,包括嵌套在另一个dropdown__menu内部 - 修饰符用于变体控制,如
dropdown--hover(悬停触发)或dropdown--click(点击触发),而非层级标识
hover 闪退?大概率是 .dropdown__toggle:hover + .dropdown__menu 断链了
CSS 兄弟选择器 你想让二级菜单缩进 20px、z-index 高一点、箭头方向朝右——这些不是“它属于第二层”导致的,而是“它出现在子级上下文”带来的表现差异。BEM 不鼓励用父级上下文去命名子元素(如 真正容易被忽略的点是:BEM 的 block 划分不是看视觉位置,而是看**职责是否可剥离、是否能脱离当前上下文独立存在并测试**。一个 dropdown 组件,应该能单独跑 demo 页面、能被 Storybook 加载、能接受 props 控制展开逻辑——如果它只能活在 .dropdown__toggle:hover + .dropdown__menu 要求两个元素必须是**紧邻兄弟节点**。只要中间插了一个无关 wrapper(比如 Vue 的 、React 的 、或手写的
(无间隔).dropdown:hover .dropdown__menu,但需确保 .dropdown 有 position: relative 以约束绝对定位的 menu:focus-within 替代 hover,避免纯 hover 在触屏设备上不可用子 dropdown 的样式怎么和父级区分?别靠前缀,用 modifier + DOM 层级
dropdown--in-nav-item),而应通过 modifier 表达自身状态,并利用 CSS 层级关系控制继承。
dropdown--nested 修饰符,定义基础缩进、过渡延迟等共性.dropdown__menu .dropdown--nested .dropdown__menu 这类后代选择器微调嵌套深度的表现,而不是靠类名拼接dropdown__menu--secondary:menu 本身不是 block,不能加 modifier;要改的是整个 dropdown 实例的状态为什么 comment--nested 可行,但 nav__item__dropdown 不行?关键在“是否可复用”
comment--nested 合理,是因为所有评论(无论嵌套几层)都共享同一套语义:作者、内容、时间、回复按钮——它们本质是同一 block 的不同实例。而 nav__item__dropdown 错在把 dropdown 当作 nav 的附属品,忽略了它在搜索框、用户头像菜单、甚至表单内也能复用的事实。nav__item 里,那它就不是 block,只是 nav 的一个私有实现细节。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











