状态样式
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 修饰符
使用 group 和 group-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 修饰符
使用 peer 和 peer-*: 实现兄弟元素状态影响:
<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 即可实现进入过渡效果
- 与
open、popover等状态配合使用
工作原理:@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:前缀 - 父元素状态:使用
group和group-hover:等 - 兄弟元素状态:使用
peer和peer-*:等 - 暗黑模式:使用
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 的自定义配置。