最稳妥的无js选项卡方案是用input[type="radio"]+label纯css实现,依赖radio互斥性控制显隐,需同名name、for/id关联、相邻兄弟选择器,并同步aria属性确保可访问性。

用 input[type="radio"] + label 实现无 JS 选项卡
纯 CSS 实现最稳妥,兼容性好、无需监听事件、SEO 友好。核心是利用 radio 的互斥特性控制显示隐藏。
关键点:所有 input 必须同名(name="tab"),每个 label 用 for 关联对应 input,目标内容块用相邻兄弟选择器(input:checked + .tab-content)或通用兄弟选择器控制显隐。
- 每个选项卡标题用
label包裹,for值必须与对应input的id一致 - 内容区必须紧跟在对应
input后面,否则+选择器不生效 - 默认选中靠把第一个
input加上checked属性,别漏掉 - 用
display: none隐藏未选中内容,不要用visibility: hidden,否则仍占布局空间
用 aria-controls 和 aria-selected 做基础可访问性
屏幕阅读器用户依赖 ARIA 属性理解当前状态。只加 CSS 不够,必须同步更新语义属性。
手动切换时(比如用 JS 控制),要确保:button 或 tab 元素有 aria-selected="true",对应内容区有 id,且该 id 被写进 aria-controls 值里。
-
role="tablist"放在容器上,子项用role="tab" - 内容区用
role="tabpanel",并设置aria-labelledby指向对应 tab 的id - 初始状态:默认选中的 tab 要有
aria-selected="true",对应 panel 要aria-hidden="false" - JS 切换时,必须同时改
aria-selected、aria-hidden和tabindex(非激活 tab 应设为-1)
用 details/summary 快速实现单个可折叠选项卡
如果只要一个可展开/收起的面板(比如 FAQ),details 是原生、轻量、无障碍友好的选择,完全不用 JS。
它自带展开状态管理、键盘支持(空格/回车切换)、默认箭头图标,且所有主流浏览器都支持(包括 Safari 12.1+)。
- 不要给
summary加onclick或额外事件监听,会干扰原生行为 - 如需自定义箭头,用
summary::marker覆盖,别用伪元素遮挡原生提示 -
details[open]CSS 选择器可用于样式控制,但注意 Safari 对该伪类的支持略晚于其他浏览器 - 不适用于多选卡互斥场景——
details是独立开关,无法强制关闭其他同类元素
避免用 display: contents 破坏 tabpanel 的语义结构
有人为了“简化 DOM”把 tab 内容包裹层设成 display: contents,结果导致 role="tabpanel" 失效,屏幕阅读器直接跳过内容。
因为 display: contents 会让元素自身从渲染树消失,其 role 和所有 ARIA 属性失效,父容器也无法正确识别其语义边界。
- 如果真要精简 DOM,优先考虑用
div替代冗余 wrapper,而不是用display: contents - 任何带
role的元素都不能设display: contents,这是 WCAG 明确不推荐的模式 - 测试方法:用 Chrome DevTools 的 Accessibility 面板查看该节点是否还在 AX Tree 中
display,忘了更新 aria-hidden 和 aria-selected。这点在键盘导航时立刻暴露。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











