不能靠 :checked + z-index + opacity 实现可靠 tab 切换——它会破坏互斥逻辑、丢失可访问性、且无法默认选中;:checked 必须搭配兄弟选择器(~ 或 +)才能建立状态与面板的声明式映射,z-index 无实际切换作用,opacity 仅适用于过渡动画,初始选中必须依赖 html 的 checked 属性。

不能靠 :checked + z-index + opacity 实现可靠 Tab 切换——它会破坏互斥逻辑、丢失可访问性、且无法默认选中。
为什么 :checked 必须搭配兄弟选择器(~ 或 +)
浏览器只在 input[type="radio"] 的 :checked 状态真实改变时触发样式响应,而这个状态变化必须由用户点击 label(通过 for 绑定)或直接点选 radio 触发。仅用 z-index 和 opacity 无法“驱动”该状态切换;它们只是视觉修饰,不参与状态绑定。一旦脱离 ~ .panel 这类选择器链,CSS 就完全不知道哪个内容块该显示。
-
:checked ~ .panel是声明式映射:选中某个 radio → 后续同级的 .panel 显示 -
.panel:nth-of-type(1) { opacity: 1; z-index: 2; }是静态规则,和任何 radio 都无关联 - 强行用 JS 或 CSS 变量模拟“当前激活索引”,就已脱离纯 CSS
:checked范畴
z-index 在 Tab 切换中几乎没用,反而容易引发层叠错乱
Tab 内容块本应是互斥显示,不是叠加堆叠。用 z-index 让多个 .panel 同时存在 DOM 中并靠层级控制可见性,会导致:
- 屏幕阅读器仍会朗读所有
.panel(即使opacity: 0),违反可访问性原则 - 键盘焦点可能落在隐藏面板的可聚焦元素上,造成操作迷失
- 滚动容器内若内容高度不同,
z-index堆叠会干扰overflow行为 - 移动端双指缩放或快速滑动时,渲染层可能残留旧内容残影
真正该用 opacity 的地方只有一个:做淡入淡出过渡
opacity 是少数几个支持 CSS transition 且不影响布局与语义的属性。但它必须配合真正的显示/隐藏控制逻辑,不能替代。
- 正确组合:
.panel { opacity: 0; visibility: hidden; height: 0; overflow: hidden; transition: opacity 0.25s ease; } - 激活规则:
input#tab2:checked ~ #content2 { opacity: 1; visibility: visible; height: auto; } - 禁止写法:
input:checked ~ .panel { z-index: 1; }—— 它什么都不会切换 - 注意:不要对
height做 transition(不支持平滑动画),只用它配合overflow: hidden控制展开收起
初始选中必须靠 HTML 的 checked 属性,不是 CSS
哪怕你把 opacity 和 z-index 写得再精细,如果第一个 input 没带 checked,页面加载后所有内容块都是隐藏状态,用户第一次点击前看不到任何内容。
- 必须写成:
<input type="radio" name="tab" id="tab1" checked> - 不能写成:
<input type="radio" name="tab" id="tab1" checked>(HTML5 中checked是布尔属性,无值即可) - 动态插入时,JS 必须同步设置
el.checked = true,否则:checked伪类不匹配 - 别试图用
:first-of-type:checked模拟默认态——它不会让浏览器真正选中该 radio
最常被忽略的一点:结构里任何一个 for 漏写、name 拼错、或内容块没放在 radio 同一父容器下,整个切换都会静默失效——没有报错,没有提示,只有点击没反应。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











