必须用 ~(通用兄弟选择器)是因为它能匹配 radio 后所有同级兄弟元素,容错性强;+ 只匹配紧邻下一个,结构变动即失效;:checked > .panel 无效因 .panel 非其子元素;name 属性必须一致且不可省略,否则互斥失效;隐藏需用 visibility + height + overflow 组合以兼顾可访问性与动画。

纯 CSS Tab 切换必须用 input[type="radio"] + :checked + ~(通用兄弟选择器),缺一不可;靠 z-index 或 opacity 单独控制显示/隐藏,一定会失效。
为什么一定要用 ~ 而不是 + 或其他选择器?
浏览器只在 input[type="radio"] 的 :checked 状态真实改变时触发样式响应,而这个状态绑定必须靠选择器“把状态传下去”。~ 匹配后续所有同级兄弟元素,只要内容块和 radio 在同一父容器内、且位置在它后面,就能命中——哪怕中间插了 <label></label> 或说明文字。+ 只匹配紧邻的下一个兄弟,结构稍一变动就断链;:checked > .panel 根本无效,因为 .panel 不是 radio 的子元素。
-
~容错强:适合真实 DOM 中常有插入元素的场景(比如加提示文案、图标) -
+性能略优但脆弱:仅当内容块严格紧贴 radio 后面时可用 - 绝对不能写成
:checked .panel(后代选择器)或:checked > .panel(子选择器),它们不生效
name 属性写错或漏掉,整个切换就静默失败
radio 的互斥逻辑完全由 name 属性驱动。如果多个 radio 的 name 值不一致(比如拼错、大小写混用、漏写),点击后会出现多个同时 :checked,对应的内容块就会一起显示,页面逻辑全乱。
- 所有参与切换的 radio 必须写相同的
name,例如name="tab" - 即使只有一个 tab 也要写
name,否则后续加新 tab 时极易出错 - 不能用 class、data-* 或其他属性替代
name,浏览器只认这个属性
内容块隐藏方式直接影响可访问性和动画效果
用 display: none 会让屏幕阅读器跳过内容,也导致 transition 在 height 上无法平滑过渡。真正稳妥的做法是组合视觉控制与语义保留:
- 初始状态设为
visibility: hidden; height: 0; overflow: hidden; - 激活时设为
visibility: visible; height: auto; opacity: 1; - 过渡只加在
opacity或transform上,height: auto本身不支持 transition - 必须显式给默认项的 radio 加
checked属性(不是checked="true"),否则首次加载不显示
最常卡住人的不是语法多难,而是 DOM 结构里少了一个 for 属性、name 拼错半个字母、或者误把 .panel 放到了 radio 的父容器外——这些错误都不报错,只是切换完全不动。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











