Chapter 05

状态与交互

掌握 hover/focus/active、group/peer 联动与 has: 父选择器,打造专业的交互体验

1. 基础伪类前缀

Tailwind 为所有常用 CSS 伪类提供前缀,格式与响应式断点前缀一致:状态:工具类

<!-- hover: 鼠标悬浮 -->
<button class="bg-cyan-500 hover:bg-cyan-600 hover:shadow-lg
                   transition-all duration-200">
  悬浮变深色
</button>

<!-- focus: 键盘聚焦(无障碍重要!)-->
<input class="
  border border-gray-300
  focus:outline-none
  focus:ring-2 focus:ring-cyan-500 focus:ring-offset-2
  focus:border-cyan-500
  rounded-lg px-4 py-2
"/>

<!-- active: 鼠标按下 -->
<button class="
  bg-cyan-500 hover:bg-cyan-600
  active:bg-cyan-700 active:scale-95
  transition-all
">按下有缩小效果</button>

<!-- disabled: 禁用状态 -->
<button
  class="bg-cyan-500 disabled:bg-gray-300 disabled:cursor-not-allowed
                   disabled:opacity-50"
  disabled
>禁用按钮</button>

<!-- checked: 复选框选中 -->
<input type="checkbox" class="accent-cyan-500" />

2. group / peer 联动

这是 Tailwind 中极其强大的功能:根据父元素兄弟元素的状态来改变目标元素的样式,无需任何 JavaScript。

group:父元素状态联动子元素

在父元素上加 group class,子元素使用 group-hover:group-focus: 等前缀。

<!-- 悬浮卡片:鼠标悬浮整个卡片时,箭头图标右移 -->
<div class="group flex items-center gap-3 p-4 rounded-xl
                border border-gray-200 hover:border-cyan-500
                hover:bg-cyan-50 cursor-pointer transition-all">
  <div class="w-10 h-10 bg-cyan-100 rounded-lg flex items-center justify-center">
    🎨
  </div>
  <div class="flex-1">
    <p class="font-semibold text-gray-900 group-hover:text-cyan-600">
      Tailwind CSS v4
    </p>
    <p class="text-sm text-gray-500">utility-first CSS 框架</p>
  </div>
  <!-- 悬浮时箭头向右移动 -->
  <svg class="w-5 h-5 text-gray-400 group-hover:text-cyan-500
                   group-hover:translate-x-1 transition-transform">
    ...
  </svg>
</div>

peer:兄弟元素状态联动

在目标兄弟元素上加 peer class,后续兄弟元素使用 peer-hover:peer-focus:peer-checked: 等前缀。

<!-- 表单验证提示:输入框 focus 时显示提示文字 -->
<div>
  <input
    type="email"
    class="peer border rounded-lg px-3 py-2 w-full
                   focus:ring-2 focus:ring-cyan-500 focus:border-cyan-500
                   invalid:border-red-400 invalid:ring-red-200"
    placeholder="输入邮箱"
    required
  />
  <!-- peer-invalid: 当 input 验证失败时显示 -->
  <p class="hidden peer-invalid:block mt-1 text-sm text-red-500">
    请输入有效的邮箱地址
  </p>
  <!-- peer-focus: 当 input 聚焦时显示提示 -->
  <p class="hidden peer-focus:block mt-1 text-xs text-cyan-500">
    输入格式:user@example.com
  </p>
</div>
<!-- 自定义 checkbox 开关:peer-checked 控制样式 -->
<label class="flex items-center gap-3 cursor-pointer">
  <input type="checkbox" class="peer sr-only">
  <!-- sr-only 隐藏原始 checkbox,sr = screen reader -->
  <div class="
    w-11 h-6 bg-gray-300 rounded-full
    peer-checked:bg-cyan-500
    relative transition-colors
    after:content-[''] after:absolute after:top-0.5 after:left-0.5
    after:w-5 after:h-5 after:rounded-full after:bg-white
    after:transition-transform
    peer-checked:after:translate-x-5
  "></div>
  <span class="text-sm font-medium">开启通知</span>
</label>

3. focus-within 与 focus-visible

<!-- focus-within: 当容器内任一子元素聚焦时,容器本身改变样式 -->
<div class="border border-gray-300 focus-within:border-cyan-500
                   focus-within:ring-2 focus-within:ring-cyan-100
                   rounded-xl p-4 transition-all">
  <label class="block text-sm text-gray-600 mb-1">搜索</label>
  <input class="w-full outline-none bg-transparent" placeholder="输入关键词...">
</div>

<!-- focus-visible: 只对键盘导航聚焦生效(鼠标点击不显示焦点环)-->
<button class="
  rounded-lg px-4 py-2 bg-cyan-500 text-white
  focus:outline-none
  focus-visible:ring-2 focus-visible:ring-cyan-600 focus-visible:ring-offset-2
">无障碍按钮</button>

4. has: 父选择器

has: 是 CSS 中新增的父选择器(CSS Selectors Level 4),Tailwind v4 原生支持它作为状态前缀。当元素内部包含匹配的子元素时,该元素自身的样式生效。

<!-- has-[input:checked]: 当内部 input 被选中时 -->
<label class="
  flex items-center gap-3 p-4 rounded-xl border cursor-pointer
  border-gray-200 has-[:checked]:border-cyan-500
  has-[:checked]:bg-cyan-50 transition-all
">
  <input type="radio" name="plan" class="accent-cyan-500">
  <div>
    <p class="font-semibold">专业版</p>
    <p class="text-sm text-gray-500">¥99/月</p>
  </div>
</label>

<!-- has-[.error]: 当容器内有 .error 元素时显示红色边框 -->
<div class="border rounded-lg p-4 has-[.error]:border-red-400">
  <input class="w-full" placeholder="用户名">
  <p class="error text-red-500 text-sm mt-1">用户名已被占用</p>
</div>

本章小结:Tailwind 的状态前缀让你无需 JavaScript 即可实现大量交互效果。核心是理解 group(父→子联动)和 peer(兄→弟联动)的工作原理——它们是纯 CSS 实现复杂交互的关键。has: 选择器是 v4 带来的新能力,支持真正的父选择器样式绑定。