hidden属性是最稳妥的标签切换方案,它原生暂停video/iframe、处理焦点与可访问性,配合data-tab映射和role="tablist"实现语义化、无障碍切换,首次需手动移除默认面板hidden以防白屏。

用 hidden 属性控制显隐最稳妥,不是靠 display: none 或 class 切换——它会暂停 <video></video>、<iframe></iframe>,自动处理焦点和可访问性状态,且语义清晰、CSS 可统一接管。
怎么用 hidden 实现基础切换
核心是按钮和面板通过 data-tab 建立映射,不依赖 DOM 顺序或 ID,避免组件复用时冲突。
- 每个标签按钮用
<button type="button"></button>,防止意外触发表单提交 - 按钮加
data-tab="home",对应面板加id="panel-home"和hidden - 首次加载必须手动移除默认面板的
hidden,否则白屏(这是最常漏的一步) - JS 切换逻辑只需两步:
document.querySelectorAll('[role="tabpanel"]').forEach(p => p.hidden = true),再设目标面板.hidden = false
为什么别直接用 display: none 切换
它只是让浏览器“假装看不见”,但仍在渲染流里做无用功;更关键的是,它不触发媒体暂停、不释放 iframe 资源、不重置表单焦点——这不是 bug,是设计如此。
-
<video></video>在display: none下可能继续缓冲甚至播放(尤其 Safari) - 含
<input>的面板切走后,再切回时焦点丢失、滚动位置归零 - 在 Vue/React 中,
v-if销毁实例,v-show才等价于display切换 -
hidden是 HTML5 原生语义属性,CSS 可用[hidden] { display: none; }统一接管样式
怎么支持键盘导航和屏幕阅读器
没加 ARIA 的标签页,在盲人用户或键盘党眼里就是一堆不可操作的 <div>。
<ul>
<li>外层容器加 <code>role="tablist",每个按钮加 role="tab" 和 aria-controls="panel-home"
aria-selected="true",其他为 "false";对应面板设 aria-hidden="false"
ArrowLeft/ArrowRight 键,用 .focus() 移动焦点,别只改视觉 class.focus(),否则键盘用户按 Tab 还停在旧按钮上真正容易被忽略的点是:所有面板初始必须有明确的 hidden 状态(除了默认那个),且每次切换后要同步 aria-selected 和 tabindex ——漏掉任一环,键盘或读屏器就会卡住。











