用 hidden 属性切换最稳妥,它原生暂停 video/iframe、保留表单状态、自动处理焦点与可访问性;需配合 data-tab 映射、完整 ARIA 语义(role="tablist"/"tab"/"tabpanel")、键盘导航支持及避免框架条件渲染销毁组件。

用 hidden 属性切换最稳妥,不是 display: none
直接改 style.display 看似简单,但会留下一堆隐患:嵌在标签页里的 在 Safari 下可能继续缓冲, 不释放资源,含 的表单切走再切回时焦点丢失、滚动位置归零。而 hidden 是 HTML5 原生语义属性,浏览器明确知道“这部分不参与渲染、不可访问、不触发媒体加载”,还自动处理 ARIA 焦点流。
实操要点:
- 所有面板初始加
hidden,除了默认显示的那个(比如不加,加)- JS 切换逻辑极简:
document.querySelectorAll('[role="tabpanel"]').forEach(p => p.hidden = true); document.querySelector(`#panel-${tab}`).hidden = false;- 别混用
hidden和display: block—— 一旦元素有hidden,CSS 的display规则会被忽略- IE 不支持
hidden,如需兼容,回退到 class 控制display,但得自己补暂停视频、重置焦点等逻辑必须加 ARIA 语义,否则键盘和屏幕阅读器进不去
纯靠
click事件 +hidden切换,对鼠标用户没问题,但 Tab 键根本进不到标签按钮,方向键也切不了页签——这不是 bug,是没写语义导致的不可访问。关键结构要齐备:
- 外层容器加
role="tablist" - 每个标签按钮是
role="tab",当前激活项设tabindex="-1",其他设tabindex="0" - 对应面板加
role="tabpanel",并用aria-labelledby="tab-home"指向标签按钮的id - 监听
keydown,捕获ArrowLeft/ArrowRight实现键盘横向切换
别用
v-if或{show &&销毁组件} Vue/React 里常见错误:用条件渲染控制标签页显隐,比如 Vue 的
v-if="activeTab === 'home'"或 React 的{activeTab === 'home' &&。这会导致组件反复挂载/卸载,表单输入清空、定时器中断、Canvas 动画重来。} 正确做法:
- Vue:改用
v-show,保留 DOM 和组件实例 - React:用
style={{ display: activeTab === 'home' ? 'block' : 'none' }}或 CSS 类控制显隐 - 真需要销毁(比如释放大图或 WebGL 资源),应在组件卸载前手动清理,而不是依赖框架条件渲染
纯 CSS 方案只适合静态内容,且有硬伤
:target和radio + :checked都能零 JS 切换,但适用场景很窄。:target的问题:- URL 锚点能分享,但无法高亮当前标签(
a:target不生效,因为 :target 匹配的是目标元素,不是链接本身) - 不支持过渡动画,
opacity或transform在 :target 下被浏览器禁用 - 刷新后状态还在,但首次加载没锚点时,得靠
:first-of-type显式显示第一个,容易和 :target 冲突
radio + :checked的问题:- 结构强耦合:label 必须紧跟 radio,内容区必须是兄弟节点,DOM 顺序一变就失效
- 无法用空格键切换(
支持,它原生可聚焦) - 移动端点击热区容易小于 44×44px,导致点不中,得额外加 padding 或伪元素撑开
复杂点不在“怎么切”,而在“切完之后资源是否真正停了、焦点是否还在、键盘能否操作、URL 是否可同步”。这些细节不补全,标签页只是个视觉动效,不是可用的交互控件。
- JS 切换逻辑极简:
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











