Tailwind CSS 核心语法篇 九:互动性

9. 互动性

互动性是连接用户与界面的桥梁。它不仅仅是关于点击和悬停,还包括光标的反馈、表单的可用性、滚动体验以及对用户输入的响应。Tailwind 提供了一整套工具来精细地控制这些交互行为,从而创造出直观、流畅且用户友好的体验。

9.1 光标与指针事件

这两个属性共同决定了用户如何与一个元素进行最基础的交互。

  • cursor: 改变鼠标悬停在元素上时的指针样式,为用户提供关于元素功能的即时视觉线索。
  • pointer-events: 控制元素是否能成为鼠标事件的目标。pointer-events-none 是一个强大的工具,可以让一个元素在视觉上存在,但允许点击“穿透”它,作用于其下方的元素。
类别常用类名说明
光标cursor-pointer手型。表示元素是可点击的,如按钮、链接。
光标cursor-not-allowed禁止。表示操作不可用,通常用于禁用的按钮。
光标cursor-grab抓取。表示元素是可拖动的。
事件pointer-events-none事件穿透。元素对鼠标事件“隐形”。
事件pointer-events-auto恢复正常的鼠标事件响应。

代码范例:指针事件在表单图标上的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cursor & Pointer Events</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="p-8 bg-slate-100">
<div class="w-full max-w-xs">
<label for="search" class="font-medium text-slate-700">Search</label>
<div class="relative mt-1">
<!--
这个 SVG 图标位于输入框内部,
pointer-events-none 确保即使用户点击到图标,
焦点也能正确地落在输入框上。
-->
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-slate-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
</svg>
</div>
<input type="text" id="search" class="w-full pl-10 pr-3 py-2 border border-slate-300 rounded-md">
</div>
</div>
</body>
</html>

9.2 外观与表单样式

默认情况下,浏览器会为表单元素(如 <select>, <input type="checkbox">)应用一套原生的、跨平台不一致的样式。为了实现自定义设计,我们首先需要移除这些原生样式。

  • appearance-none: 这是自定义表单元素的 第一步。它会移除浏览器强加的大部分默认样式,让你能像对待普通 div 一样去设置背景、边框、内边距等。
  • accent-{color}: 一个现代 CSS 属性,用于快速改变某些表单控件(如复选框、单选按钮)的 强调色,而无需完全重置它们的样式。
  • caret-{color}: 用于改变文本输入框中 光标 的颜色。

代码范例:自定义一个下拉选择框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Custom Select</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="p-8 bg-slate-100">
<div class="w-full max-w-xs">
<label for="framework" class="font-medium text-slate-700">Framework</label>
<div class="relative mt-1">
<!--
1. appearance-none 移除了默认的下拉箭头和样式。
2. 我们用自己的 div 和 SVG 制作了一个新的箭头。
-->
<select id="framework" class="w-full pl-3 pr-10 py-2 bg-white border border-slate-300 rounded-md appearance-none">
<option>React</option>
<option>Vue</option>
<option>Svelte</option>
</select>
<div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-slate-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
</div>
</div>
</body>
</html>

9.3 滚动行为与捕捉 (Scroll Behavior & Snap)

这些工具用于增强长页面或轮播组件的滚动体验。

  • scroll-smooth: 应用于 <html> 元素时,可以使页面内的锚点链接(href="#section")产生平滑的滚动动画,而不是瞬间跳转。
  • scroll-snap: 用于创建“吸附”效果的滚动容器,常见于轮播图 (Carousel)。它需要父元素(滚动容器)和子元素(滚动项)的配合。

滚动捕捉 (Scroll Snap) 的实现配方:

  1. 容器: snap-x (水平) 或 snap-y (垂直),以及 snap-mandatory (强制吸附) 或 snap-proximity (接近时吸附)。
  2. 滚动项: snap-start, snap-center, 或 snap-end,定义了子元素与容器对齐的位置。
  3. 滚动边距/内边距: scroll-m-*scroll-p-*,用于在吸附时添加偏移量,防止内容被固定的导航栏等元素遮挡。

代码范例:一个水平滚动的图片轮播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scroll Snap Carousel</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="p-8">
<!-- 1. 容器:设置 snap-x 和 snap-mandatory -->
<div class="w-full max-w-lg mx-auto flex space-x-4 overflow-x-auto pb-4 snap-x snap-mandatory">
<!-- 2. 滚动项:设置 snap-center 使其在容器中居中对齐 -->
<div class="snap-center flex-shrink-0 w-4/5">
<img src="https://picsum.photos/id/1015/500/300" class="rounded-lg">
</div>
<div class="snap-center flex-shrink-0 w-4/5">
<img src="https://picsum.photos/id/1016/500/300" class="rounded-lg">
</div>
<div class="snap-center flex-shrink-0 w-4/5">
<img src="https://picsum.photos/id/1018/500/300" class="rounded-lg">
</div>
<div class="snap-center flex-shrink-0 w-4/5">
<img src="https://picsum.photos/id/1019/500/300" class="rounded-lg">
</div>
</div>
</body>
</html>

9.4 用户选择与大小调整 (User Select & Resize)

  • user-select: 控制用户是否能够选择元素中的文本。这对于防止用户意外选中按钮或导航等 UI 元素的文本非常有用。
  • resize: 控制用户是否可以调整一个元素的尺寸,最常见的应用是 <textarea>
类别常用类名说明
选择select-none禁止选择。应用于 UI 控件,如按钮、图标。
选择select-text允许选择。应用于正文内容。
选择select-all单击全选。应用于代码块、许可证密钥等。
调整resize-none禁止调整大小。
调整resize-y仅允许垂直调整。
调整resize允许双向调整。

代码范例:代码块和不可调整大小的文本区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Select & Resize</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="p-8 space-y-6">
<div>
<label for="code-block" class="font-medium">API Key (click to select all):</label>
<!-- select-all 使得用户单击即可复制整个 key -->
<pre id="code-block" class="mt-1 p-3 bg-slate-800 text-white rounded-md select-all">
<code>user-abcdef1234567890</code>
</pre>
</div>
<div>
<label for="comment" class="font-medium">Comment (not resizable):</label>
<!-- resize-none 禁止用户调整 textarea 的大小 -->
<textarea id="comment" class="mt-1 w-full p-2 border border-slate-300 rounded-md resize-none"></textarea>
</div>
</body>
</html>