应使用tab__item--active而非is-active,因其是bem原生修饰符,语义明确、可静态存在、css独立生效且不依赖js;is-active仅为社区状态类,易被误删、需与块名共存、仅作js/a11y信号辅助。

is-active只在需要跨组件状态感知时才用
它不是样式开关,而是“这个元素当前处于某种可被外部读取的状态”的信号。比如路由模块要判断哪个tab__panel该显示、表单校验逻辑要检查.step.is-active是否已提交、屏幕阅读器需同步aria-selected="true"——这些都不是纯视觉问题,而是运行时协作需求。
常见错误现象:el.classList.toggle('is-active')后发现面板没显示,但CSS里只写了.tab__panel--active;或者用.is-active做全局显隐控制,结果.tooltip.is-active和.sidebar.is-active互相干扰。
- 必须绑定到具体块或元素:
.tab__panel.is-active合法,.is-active单独写是语义断裂 - HTML中必须硬编码组合(如
class="tab__panel is-active"),否则PurgeCSS可能误删 - JS切换时得同步处理
aria-selected、aria-current等语义属性,不能只动class
什么时候绝对不该用is-active
当状态在服务端就已确定,且不依赖JS执行时。tab__item--active应直接出现在初始HTML中,比如路由匹配后SSR渲染的导航项。此时用is-active不仅多余,还会让JS加载失败时丢失视觉反馈。
常见错误现象:把tab__item--active当成JS控制对象,用classList.toggle('is-active')去切换,却忘了CSS里根本没定义.tab__item.is-active规则;或者在PostCSS/CSS-in-JS中is-active生成顺序靠前,被后续基础样式覆盖。
-
--active修饰符必须独立生效,不依赖JS:.tab__item--active { font-weight: 600; border-bottom: 2px solid #007bff; } - 禁用
:active伪类和--active混用:点击瞬态反馈和持久选中态是两回事 - 工具链(如stylelint-bem)会报错
tab__item-active(缺双横杠)或is-active孤立使用
is-active和--active共存时怎么分工
它们不是替代关系,而是信号与表现的分离。一个管“是什么”,一个管“看起来怎样”。典型场景就是Tabs:标签用tab__item--active加底边框、变色,面板用tab__panel.is-active控制display显隐。
容易踩的坑是职责模糊:比如用is-active控制颜色,又用--active控制尺寸,结果A11y脚本查is-active以为状态已同步,实际视觉反馈却由另一个修饰符控制,断开一致性。
-
--active负责所有UI变体:背景、边框、字体、间距等 -
is-active只用于显隐、动画触发、JS查询、A11y属性同步 - 键盘支持必须同步:仅监听
click不够,keydown对Enter/Space也要触发is-active切换
构建工具对is-active的实际影响
PurgeCSS这类工具不理解“状态类”语义,只扫描硬编码的class组合。如果is-active只在JS字符串拼接中出现(如el.className = 'tab__panel ' + (isActive ? 'is-active' : '')),它大概率被删掉。
更隐蔽的问题是CSS-in-JS中动态生成的is-active类名,可能因作用域隔离或哈希命名导致DevTools里看不到原始类名,调试时误以为JS没生效。
- 确保HTML模板或JS中至少有一处显式写死
class="tab__panel is-active" - 避免用
className += ' is-active',改用classList.add('is-active')保证原子性 - Tailwind用户注意:
content配置必须包含JS中所有is-active组合路径,否则会被Purge
is-active的脆弱性恰恰来自它的通用性——它不描述“谁的状态”,只声明“有状态”。一旦脱离具体块/元素上下文,就变成一把没鞘的刀。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











