跳到主要内容

状态样式

Tailwind CSS 提供了丰富的状态变体,让你能够轻松地为悬停、焦点、激活等状态添加样式。本章将详细介绍如何使用状态变体。

悬停状态

使用 hover: 前缀为悬停状态添加样式:

<button class="bg-blue-500 hover:bg-blue-700 text-white px-4 py-2 rounded">
悬停时背景变深
</button>

<a href="#" class="text-blue-500 hover:underline">
悬停时显示下划线
</a>

<div class="bg-white hover:bg-gray-100 p-4 rounded cursor-pointer">
悬停时背景变色
</div>

焦点状态

使用 focus: 前缀为焦点状态添加样式:

<input class="border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 px-4 py-2 rounded outline-none">

<textarea class="border focus:border-blue-500 focus:ring-2 focus:ring-blue-200 px-4 py-2 rounded outline-none"></textarea>

<button class="bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-300 px-4 py-2 rounded text-white">
焦点时显示环
</button>

焦点可见

使用 focus-visible: 前缀,仅在键盘导航时显示焦点样式:

<button class="bg-blue-500 focus-visible:ring-2 focus-visible:ring-blue-300 px-4 py-2 rounded text-white">
仅键盘导航时显示焦点环
</button>

激活状态

使用 active: 前缀为激活(按下)状态添加样式:

<button class="bg-blue-500 hover:bg-blue-600 active:bg-blue-800 text-white px-4 py-2 rounded">
按下时背景更深
</button>

禁用状态

使用 disabled: 前缀为禁用状态添加样式:

<button class="bg-blue-500 disabled:bg-gray-300 disabled:cursor-not-allowed text-white px-4 py-2 rounded" disabled>
禁用按钮
</button>

<input class="border disabled:bg-gray-100 disabled:text-gray-400 px-4 py-2 rounded" disabled value="禁用输入框">

也可以使用 not-disabled: 为非禁用状态添加样式:

<button class="bg-blue-500 not-disabled:hover:bg-blue-600 text-white px-4 py-2 rounded">
仅非禁用时响应悬停
</button>

选中状态

用于复选框、单选框等可选中元素:

<input type="checkbox" class="accent-blue-500 checked:accent-blue-700">

<input type="radio" class="accent-blue-500 checked:accent-blue-700">

只读状态

<input class="border readonly:bg-gray-100 px-4 py-2 rounded" readonly value="只读内容">

占位符状态

<input class="placeholder:text-gray-400 px-4 py-2 border rounded" placeholder="输入内容">

组合状态变体

可以组合多个状态变体:

<button class="bg-blue-500 hover:bg-blue-600 active:bg-blue-700 focus:ring-2 focus:ring-blue-300 disabled:bg-gray-300 disabled:cursor-not-allowed text-white px-4 py-2 rounded">
完整状态按钮
</button>

父元素状态

group 修饰符

使用 groupgroup-hover: 实现父元素悬停时改变子元素样式:

<div class="group bg-white p-4 rounded-lg shadow hover:shadow-lg cursor-pointer">
<h3 class="font-semibold group-hover:text-blue-500">标题</h3>
<p class="text-gray-600 group-hover:text-gray-800">描述内容</p>
<span class="opacity-0 group-hover:opacity-100 transition-opacity">显示详情</span>
</div>

命名组

使用命名组处理嵌套的情况:

<div class="group/card bg-white p-4 rounded-lg">
<div class="group/button">
<button class="group-hover/card:bg-blue-100 group-hover/button:bg-blue-500 px-4 py-2 rounded">
按钮
</button>
</div>
</div>

其他组状态

<div class="group">
<input class="border px-4 py-2 rounded">
<p class="hidden group-focus-within:block">输入时显示提示</p>
</div>

<div class="group">
<input type="checkbox" class="group-checked:bg-blue-500">
<span class="group-checked:font-bold">选中时加粗</span>
</div>

兄弟元素状态

peer 修饰符

使用 peerpeer-*: 实现兄弟元素状态影响:

<div>
<input type="checkbox" class="peer sr-only" id="toggle">
<label for="toggle" class="bg-gray-300 peer-checked:bg-blue-500 w-12 h-6 rounded-full cursor-pointer block relative">
<span class="absolute left-1 top-1 w-4 h-4 bg-white rounded-full peer-checked:left-7 transition-all"></span>
</label>
</div>

<div>
<input class="border peer px-4 py-2 rounded">
<p class="hidden peer-focus:block text-sm text-gray-500 mt-1">输入提示</p>
</div>

<div>
<input class="border peer invalid:border-red-500 px-4 py-2 rounded">
<p class="hidden peer-invalid:block text-sm text-red-500 mt-1">请输入有效内容</p>
</div>

暗黑模式

使用 dark: 前缀为暗黑模式添加样式:

<div class="bg-white dark:bg-gray-800 p-4 rounded-lg">
<h3 class="text-gray-900 dark:text-white font-semibold">标题</h3>
<p class="text-gray-600 dark:text-gray-300">描述内容</p>
</div>

<button class="bg-blue-500 dark:bg-blue-600 text-white px-4 py-2 rounded">
按钮
</button>

启用暗黑模式

在配置文件中设置:

export default {
darkMode: 'class', // 或 'media'
}
  • media:根据系统偏好自动切换
  • class:根据 HTML 元素的 dark 类切换

切换暗黑模式

// 检查当前模式
if (document.documentElement.classList.contains('dark')) {
// 暗黑模式
}

// 切换模式
document.documentElement.classList.toggle('dark')

打印样式

使用 print: 前缀为打印添加样式:

<div class="print:hidden">
打印时隐藏
</div>

<div class="hidden print:block">
仅打印时显示
</div>

<div class="print:text-black print:bg-white">
打印时使用黑白配色
</div>

强制颜色模式

用于高对比度模式:

<div class="forced-color-adjust-auto">
自动调整颜色
</div>

<div class="forced-color-adjust-none">
不调整颜色
</div>

动画过渡

结合状态变体实现平滑过渡:

<button class="bg-blue-500 hover:bg-blue-700 text-white px-4 py-2 rounded transition-colors duration-300">
颜色过渡
</button>

<div class="opacity-0 hover:opacity-100 transition-opacity duration-500">
透明度过渡
</div>

<div class="transform hover:scale-105 transition-transform duration-200">
缩放过渡
</div>

过渡属性

<div class="transition">过渡所有属性</div>
<div class="transition-none">无过渡</div>
<div class="transition-all">过渡所有属性</div>
<div class="transition-colors">过渡颜色</div>
<div class="transition-opacity">过渡透明度</div>
<div class="transition-shadow">过渡阴影</div>
<div class="transition-transform">过渡变换</div>

过渡时长

<div class="duration-75">75ms</div>
<div class="duration-100">100ms</div>
<div class="duration-150">150ms</div>
<div class="duration-200">200ms</div>
<div class="duration-300">300ms</div>
<div class="duration-500">500ms</div>
<div class="duration-700">700ms</div>
<div class="duration-1000">1000ms</div>

过渡延迟

<div class="delay-75">延迟 75ms</div>
<div class="delay-150">延迟 150ms</div>
<div class="delay-300">延迟 300ms</div>
<div class="delay-500">延迟 500ms</div>

过渡曲线

<div class="ease-linear">线性</div>
<div class="ease-in">加速</div>
<div class="ease-out">减速</div>
<div class="ease-in-out">加速减速</div>

实战示例

完整按钮组件

<button class="bg-blue-500 hover:bg-blue-600 active:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-300 focus:ring-offset-2 disabled:bg-gray-300 disabled:cursor-not-allowed text-white font-medium px-4 py-2 rounded transition-colors duration-200">
按钮
</button>

卡片悬停效果

<div class="group bg-white rounded-lg shadow-md hover:shadow-xl transition-shadow duration-300 overflow-hidden cursor-pointer">
<img src="image.jpg" alt="" class="w-full h-48 object-cover group-hover:scale-105 transition-transform duration-300">
<div class="p-4">
<h3 class="font-semibold group-hover:text-blue-500 transition-colors">标题</h3>
<p class="text-gray-600 mt-2">描述内容</p>
</div>
</div>

表单验证

<div class="space-y-2">
<label class="block text-gray-700">邮箱</label>
<input
type="email"
class="w-full px-4 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-300 focus:border-blue-500 invalid:border-red-500 invalid:focus:ring-red-300 invalid:focus:border-red-500"
placeholder="[email protected]"
>
<p class="text-sm text-red-500 hidden peer-invalid:block">请输入有效的邮箱地址</p>
</div>

开关组件

<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" class="sr-only peer">
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-500"></div>
<span class="ml-3 text-gray-700">开关</span>
</label>

v4.0 新增状态变体

Tailwind CSS v4.0 引入了多个新的状态变体,提供了更强大的样式控制能力。

starting 变体

starting: 变体支持 CSS 的 @starting-style 特性,用于在元素首次出现时添加过渡效果:

<!-- 弹出框入场动画 -->
<div popover id="my-popover" class="opacity-0 transition-opacity starting:opacity-0 open:opacity-100">
弹出框内容
</div>

<!-- 对话框入场动画 -->
<dialog class="scale-95 opacity-0 transition-all starting:scale-95 starting:opacity-0 open:scale-100 open:opacity-100">
对话框内容
</dialog>

starting: 变体让你能够:

  • 为新出现在 DOM 中的元素添加入场动画
  • 无需 JavaScript 即可实现进入过渡效果
  • openpopover 等状态配合使用

工作原理@starting-style 定义元素首次渲染时的样式,然后过渡到正常状态。浏览器支持正在普及中。

not-* 变体

not-* 变体用于否定其他变体、选择器或媒体查询:

<!-- 非悬停状态 -->
<div class="not-hover:opacity-75">
未悬停时半透明
</div>

<!-- 非焦点状态 -->
<input class="not-focus:border-gray-300">

<!-- 否定媒体查询(无悬停能力的设备) -->
<div class="not-hover:bg-blue-500">
在触屏设备上显示蓝色背景
</div>

<!-- 否定 supports 查询 -->
<div class="not-supports-hanging-punctuation:px-4">
不支持悬挂标点时添加内边距
</div>

生成的 CSS:

/* not-hover:opacity-75 */
.not-hover\:opacity-75:not(*:hover) {
opacity: 75%;
}

/* 媒体查询否定 */
@media not (hover: hover) {
.not-hover\:bg-blue-500 {
background-color: var(--color-blue-500);
}
}

in-* 变体

in-* 变体类似于 group-*,但不需要在父元素上添加 group 类:

<!-- 传统方式:需要 group 类 -->
<div class="group">
<span class="group-hover:text-blue-500">悬停时变蓝</span>
</div>

<!-- v4.0 新方式:无需 group 类 -->
<div>
<span class="in-hover:text-blue-500">悬停时变蓝</span>
</div>

支持的 in-* 变体:

变体说明
in-hover:祖先悬停时生效
in-focus:祖先聚焦时生效
in-active:祖先激活时生效
in-disabled:祖先禁用时生效
in-checked:祖先选中时生效
in-expanded:祖先展开时生效

in-*group-* 的区别:

  • group-* 需要显式标记父元素
  • in-* 自动匹配任意祖先元素
  • in-* 更简洁,但可能影响性能(需遍历祖先)

nth-* 变体

nth-* 变体用于根据元素位置选择子元素:

<!-- 选择第 3 个子元素 -->
<ul>
<li class="nth-3:bg-blue-100">项目 1</li>
<li class="nth-3:bg-blue-100">项目 2</li>
<li class="nth-3:bg-blue-100">项目 3(蓝色背景)</li>
<li class="nth-3:bg-blue-100">项目 4</li>
</ul>

<!-- 选择奇数位置的子元素 -->
<tr class="nth-odd:bg-gray-50">
奇数行灰色背景
</tr>

<!-- 选择偶数位置的子元素 -->
<tr class="nth-even:bg-white">
偶数行白色背景
</tr>

<!-- 选择前 3 个子元素 -->
<li class="nth-[1]:font-bold nth-[2]:font-bold nth-[3]:font-bold">
前三项加粗
</li>

<!-- 使用 nth-last-* 从后往前计数 -->
<li class="nth-last-1:border-b-0">
最后一项无下边框
</li>

常用 nth-* 变体:

变体CSS 选择器
nth-1:nth-12::nth-child(n)
nth-odd::nth-child(odd)
nth-even::nth-child(even)
nth-first::first-child
nth-last::last-child
nth-last-1:nth-last-12::nth-last-child(n)
nth-of-type-1:nth-of-type-12::nth-of-type(n)

inert 变体

inert 变体用于样式化设置了 inert 属性的元素:

<!-- 模态框打开时,背景内容设置为 inert -->
<div class="inert:opacity-50 inert:pointer-events-none">
当模态框打开时,背景内容变暗且不可交互
</div>

<!-- 禁用区域 -->
<section inert class="inert:grayscale inert:opacity-50">
这部分内容被禁用
</section>

inert 属性会让元素及其所有子元素:

  • 不可聚焦
  • 不可编辑
  • 不响应点击事件
  • 从辅助技术中隐藏

open 变体

open: 变体用于样式化 <details><dialog>[popover] 元素的打开状态:

<!-- details 元素 -->
<details class="open:bg-gray-50">
<summary class="cursor-pointer">点击展开</summary>
<div class="p-4">展开后的内容</div>
</details>

<!-- dialog 元素 -->
<dialog class="open:opacity-100 open:scale-100 opacity-0 scale-95 transition-all">
对话框内容
</dialog>

<!-- popover 元素 -->
<div popover class="open:opacity-100 opacity-0 transition-opacity">
弹出框内容
</div>

placeholder-shown 变体

placeholder-shown: 变体在输入框显示占位符时生效:

<input 
placeholder="请输入内容"
class="placeholder-shown:border-gray-300 focus:border-blue-500"
>

<!-- 结合 label 实现浮动标签 -->
<div class="relative">
<input
id="email"
placeholder=" "
class="peer pt-4 px-4 pb-1 border rounded"
>
<label
for="email"
class="absolute left-4 top-3 transition-all peer-placeholder-shown:top-3 peer-placeholder-shown:text-base peer-focus:top-1 peer-focus:text-sm"
>
邮箱地址
</label>
</div>

autofill 变体

autofill: 变体用于样式化浏览器自动填充的输入框:

<input 
type="text"
class="border focus:border-blue-500 autofill:bg-yellow-50 autofill:border-yellow-300"
>

数据属性变体

可以直接使用 data-* 属性作为变体:

<!-- 自定义数据属性 -->
<div data-active class="data-active:bg-blue-500 data-active:text-white">
激活状态
</div>

<!-- 数据属性开关 -->
<button data-pressed="true" class="data-pressed:bg-blue-500">
按钮
</button>

<!-- 多种数据状态 -->
<div
data-size="sm"
class="data-size-sm:p-2 data-size-md:p-4 data-size-lg:p-6"
>
根据数据属性调整内边距
</div>

ARIA 状态变体

ARIA 属性也可以作为变体使用:

<!-- aria-expanded -->
<button aria-expanded="true" class="aria-expanded:font-bold aria-expanded:bg-blue-100">
展开按钮
</button>

<!-- aria-checked -->
<div role="checkbox" aria-checked="true" class="aria-checked:bg-blue-500">
复选框
</div>

<!-- aria-selected -->
<option aria-selected="true" class="aria-selected:bg-blue-500 text-white">
选中项
</option>

<!-- aria-disabled -->
<button aria-disabled="true" class="aria-disabled:opacity-50 aria-disabled:cursor-not-allowed">
禁用按钮
</button>

<!-- aria-invalid -->
<input aria-invalid="true" class="aria-invalid:border-red-500">

field-sizing 工具类(v4.0)

field-sizing 用于自动调整表单元素大小:

<!-- 自动调整文本框高度 -->
<textarea class="field-sizing-content resize-none">
内容增加时自动增高
</textarea>

<!-- 固定大小(默认) -->
<input class="field-sizing-fixed">

<!-- 自动调整宽度 -->
<input class="field-sizing-content w-min">

color-scheme 工具类(v4.0)

color-scheme 用于控制浏览器原生控件(如滚动条)的颜色方案:

<!-- 仅亮色模式 -->
<div class="color-scheme-light">
滚动条始终为亮色
</div>

<!-- 仅暗色模式 -->
<div class="color-scheme-dark">
滚动条始终为暗色
</div>

<!-- 自动跟随系统 -->
<div class="color-scheme-normal">
跟随系统偏好
</div>

<!-- 同时支持两种模式 -->
<div class="color-scheme-light-dark">
根据当前主题显示对应滚动条
</div>

配合暗黑模式使用:

<div class="color-scheme-light dark:color-scheme-dark">
暗黑模式下滚动条也会变暗
</div>

小结

本章介绍了 Tailwind CSS 的状态变体:

基础状态变体

  • 悬停状态:使用 hover: 前缀
  • 焦点状态:使用 focus:focus-visible: 前缀
  • 激活状态:使用 active: 前缀
  • 禁用状态:使用 disabled: 前缀
  • 父元素状态:使用 groupgroup-hover:
  • 兄弟元素状态:使用 peerpeer-*:
  • 暗黑模式:使用 dark: 前缀
  • 打印样式:使用 print: 前缀
  • 动画过渡:结合状态变体实现平滑过渡

v4.0 新增变体

  • starting: - 元素首次出现时的样式
  • not-* - 否定其他变体或选择器
  • in-* - 无需 group 类的祖先状态选择
  • nth-* - 根据元素位置选择
  • inert: - 样式化 inert 元素
  • open: - 样式化打开状态的元素
  • placeholder-shown: - 占位符显示时的样式
  • autofill: - 浏览器自动填充时的样式
  • data-* - 自定义数据属性变体
  • aria-* - ARIA 状态变体

v4.0 新增工具类

  • field-sizing - 自动调整表单元素大小
  • color-scheme - 控制浏览器控件颜色方案

下一章,我们将学习 Tailwind CSS 的自定义配置。