peer-checked 不生效的根本原因是复选框未作为目标元素的前一个兄弟节点且未正确隐藏:必须用 absolute opacity-0 w-0 h-0 p-0 m-0 组合隐藏原生 checkbox,确保可访问性与交互性。

直接用 @tailwindcss/forms 插件后,peer-checked 类不会自动生效——不是你写错了,是结构、定位或隐藏方式没配对。
为什么 peer-checked 完全没反应?
根本原因在于 peer 选择器的硬性要求:复选框必须是目标元素的**前一个兄弟节点**,且自身必须是原生 <input type="checkbox">,不能被 div 包裹、不能加额外 class、不能用 display: none 隐藏。
-
peer不识别hidden或opacity: 0的 input —— 它只认“存在且可交互”的兄弟节点 - 父容器没设
relative?那peer-checked:translate-x-2这类定位类会失效(因为没有定位上下文) - 用了
appearance-none但没补position: absolute和opacity: 0?插件默认只清样式,不移出渲染流,input 仍占位、可能遮挡 label 点击区
怎么安全隐藏原生 checkbox 并保留可访问性?
别用 display: none 或 visibility: hidden——它们会让控件无法聚焦、无法被屏幕阅读器识别、也无法响应点击。正确做法是组合隐藏:
- 必须同时写:
absolute opacity-0 w-0 h-0 p-0 m-0(Tailwind 中对应absolute opacity-0+ 尺寸归零) - 或更彻底:用
clip: rect(0, 0, 0, 0)(需在@layer base里手写 CSS,因 Tailwind 不提供该工具类) - 确保
<label for="xxx">和<input id="xxx">关联正确;若用peer,则结构必须为:<input ...><div class="peer-checked:bg-blue-500"></div>
自定义勾选标记时容易忽略的三个细节
视觉上画个对勾不难,但可访问性和一致性常被跳过:
立即学习“前端免费学习笔记(深入)”;
- 未选中态的伪元素(如
label::before)必须显式声明content: ""和display: inline-block,否则不渲染 - 勾选图标建议用内联 SVG 而非 Unicode 字符(如
'\2713'),避免字体 fallback 导致大小/颜色错乱,尤其深色模式下 - SVG 必须加
aria-hidden="true",否则 VoiceOver 会重复播报“勾选”两次(一次来自checked状态,一次来自图标)
要不要用 @tailwindcss/forms?
要用,但别指望它帮你完成全部。它只做两件事:清掉原生样式(appearance-none)、加基础 focus ring。所有视觉定制(边框颜色、对勾动画、禁用态灰度)都得你自己补。
- 禁用态必须手动加:
disabled:opacity-50 disabled:cursor-not-allowed,同时 HTML 上保留disabled属性和aria-disabled="true" - 焦点环颜色要满足 WCAG 对比度要求(至少 3:1),深色背景上别用默认
ring-blue-500 - 动画优先用
transform: scale(0) → scale(1),别用opacity过渡——缩放更清晰,无模糊或锯齿
最复杂的地方不在怎么画对勾,而在让那个对勾在键盘导航、高对比度模式、屏幕阅读器里都表现一致——这些没法靠一个 peer-checked:bg-green-500 解决。



















