Tab应为独立块名,结构为.tab、.tab__list、.tab__item、.tab__panel;修饰符用--active;多Tab组需唯一块名或JS作用域隔离;须同步aria-selected/aria-hidden及键盘事件。

Tab选项卡的BEM结构怎么写才不破坏命名隔离
BEM要求每个块(Block)独立、可复用,tab必须是顶层块名,不能嵌套在nav或header里定义。常见错误是把tab写成nav__tab——这会让组件失去跨上下文复用能力,也导致状态修饰符无法统一管理。
正确结构应为:
.tab { }
.tab__list { }
.tab__item { }
.tab__panel { }
tab__item和tab__panel之间靠data-tab-id或aria-controls关联,而非DOM层级或CSS父子选择器——BEM禁止用.tab__item .tab__panel这类嵌套选择器。
选中状态该用is-active还是--active修饰符
BEM官方推荐使用双横线--表示修饰符,所以tab__item--active是标准写法;is-active属于“布尔型修饰符”变体,虽常见但非BEM原生,容易和JS类名混淆(比如classList.toggle('is-active')),增加维护成本。
实际切换时,只操作tab__item和对应tab__panel的修饰符,不操作父块tab本身:
-
tab__item--active控制按钮高亮、焦点、z-index -
tab__panel--active控制显示/隐藏(用display或visibility,避免仅靠opacity: 0) - JS中用
element.classList.toggle('tab__item--active'),别漏掉tab__前缀
多个Tab组共存时如何避免修饰符冲突
同一页面有user-tab和setting-tab时,不能都用tab__item--active——CSS会互相覆盖。解决方案只有两个:
- 每个Tab块使用唯一块名:
user-tab__item--active、setting-tab__item--active,JS初始化时绑定到具体块实例 - 用属性选择器限定作用域:
[data-tab-group="user"] .tab__item--active,但会削弱BEM的语义清晰性,且增加CSS权重
更稳妥的做法是:用JS控制时,只在当前tab块范围内查找.tab__item,而不是document.querySelectorAll('.tab__item--active')——后者会跨块误操作。
用aria-selected和aria-hidden同步BEM修饰符
纯CSS修饰符无法被读屏器识别,必须同步WAI-ARIA属性。每次JS添加tab__item--active,也要设置aria-selected="true";同理,tab__panel--active要配aria-hidden="false"(未激活则为"true")。
注意两点:
- 不要用
aria-expanded——那是折叠面板(accordion)的语义,Tab不是展开关系 -
tabindex="0"只加在tab__item上,tab__panel默认不可聚焦,除非内容需要键盘导航 - 键盘支持(←→/Home/End)逻辑必须和修饰符更新严格同步,否则视觉状态和焦点状态脱节
修饰符只是视觉表征,真正的状态同步靠JS驱动+ARIA属性+键盘事件三者咬合。漏掉任意一环,都会让BEM结构变成“好看但不好用”的空壳。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











