应使用 data-tab 关联 + hidden 属性控制标签页显隐;因 display: none 不暂停视频、不释放 iframe、不重置焦点,而 hidden 具备语义化暂停、上下文清理和无障碍支持。

直接用 data-tab 关联 + hidden 属性控制显隐,是最轻量、最稳妥的方案。别碰 display: none,它不暂停视频、不释放 iframe、不重置表单焦点,看似简单,实则埋雷。
为什么不能只用 display: none 切换标签页
很多人写完 JS 一跑通就收工,结果在 Safari 里 <video></video> 还在后台缓冲,<iframe></iframe> 仍在加载第三方脚本,用户切走再切回,<input> 焦点没了、滚动位置归零、定时器断了——这不是 bug,是 display: none 的设计行为。
-
hidden是语义化属性:浏览器会主动暂停媒体、丢弃 iframe 上下文、忽略 tab 键导航 - 它天然支持 CSS 选择器
[hidden],样式可统一控制 - 无障碍支持开箱即用:屏幕阅读器自动跳过
hidden元素,无需手动设aria-hidden="true"
data-tab 和 id 怎么配才不冲突
别用 getElementById() 直接查,ID 必须全局唯一,但组件可能复用多次;改用 data-tab 做映射,解耦更干净。
- 按钮写
<button type="button" data-tab="home">首页</button> - 对应面板写
<div id="panel-home" role="tabpanel">...</div>(注意前缀一致) - JS 中用
document.querySelector(`#panel-${tab}`)查找,比拼 ID 字符串更安全 - 首次加载时必须手动移除默认面板的
hidden,否则首屏白屏
键盘导航和无障碍怎么补全
纯鼠标点击的标签页,在键盘用户或屏幕阅读器下等于不可用。必须补三样东西:
立即学习“前端免费学习笔记(深入)”;
- 外层容器加
role="tablist" - 每个按钮加
role="tab"、tabindex="0",激活项设tabindex="-1" - 每个面板加
role="tabpanel",并用aria-labelledby="btn-home"指向对应按钮的id - 监听
keydown,对ArrowLeft/ArrowRight实现方向键切换
框架里用 v-if 或 {show && <panel>}</panel> 就错了
Vue 的 v-if、React 的条件渲染,本质是销毁/重建组件实例。表单输入清空、useEffect 重跑、Canvas 动画中断——这些不是性能问题,是状态丢失。
- 框架中应改用
v-show(Vue)或style={{ display: show ? 'block' : 'none' }}(React),等价于hidden的语义 - 更推荐封装成自定义 Hook / Composable,把
hidden切换逻辑抽出来,避免重复判断 - 如果内容含 Web Components 或第三方库初始化逻辑,务必检查其是否支持“隐藏后恢复”
真正难的不是让标签页动起来,而是让 iframe 不偷跑、让表单不丢值、让键盘用户能按 Tab 进来、按方向键切换——这些细节不处理,功能就算“能用”,也算不上可用。



















