Skip to content

用户交互

CSS 提供了丰富的属性来控制用户与页面的交互方式。从鼠标光标到文本选择,从触摸行为到滚动控制,这些属性直接影响用户体验。

cursor 鼠标光标#

常用光标类型#

.default {
cursor: default;
} /* 默认箭头 */
.pointer {
cursor: pointer;
} /* 手型,表示可点击 */
.text {
cursor: text;
} /* 文本输入 */
.move {
cursor: move;
} /* 移动 */
.not-allowed {
cursor: not-allowed;
} /* 禁止 */
.wait {
cursor: wait;
} /* 等待/加载 */
.progress {
cursor: progress;
} /* 后台处理中 */
.help {
cursor: help;
} /* 帮助 */
.crosshair {
cursor: crosshair;
} /* 十字准心 */
.grab {
cursor: grab;
} /* 抓取 */
.grabbing {
cursor: grabbing;
} /* 抓取中 */

调整大小光标#

.resize-ew {
cursor: ew-resize;
} /* 左右 */
.resize-ns {
cursor: ns-resize;
} /* 上下 */
.resize-nwse {
cursor: nwse-resize;
} /* 左上-右下 */
.resize-nesw {
cursor: nesw-resize;
} /* 右上-左下 */
.col-resize {
cursor: col-resize;
} /* 列调整 */
.row-resize {
cursor: row-resize;
} /* 行调整 */

缩放光标#

.zoom-in {
cursor: zoom-in;
}
.zoom-out {
cursor: zoom-out;
}

自定义光标#

.custom {
cursor: url('/cursors/custom.png'), auto;
}
/* 带热点位置 */
.custom-hotspot {
cursor:
url('/cursors/crosshair.png') 16 16,
crosshair;
}
/* 多个回退 */
.with-fallback {
cursor: url('/cursors/fancy.cur'), url('/cursors/fancy.png'), pointer;
}

实用示例#

/* 可点击元素 */
button,
a,
[role='button'] {
cursor: pointer;
}
/* 禁用状态 */
button:disabled,
.disabled {
cursor: not-allowed;
opacity: 0.5;
}
/* 拖拽元素 */
.draggable {
cursor: grab;
}
.draggable:active {
cursor: grabbing;
}
/* 可调整大小 */
.resizable {
cursor: nwse-resize;
}

pointer-events 指针事件#

控制元素是否响应鼠标/触摸事件:

.clickable {
pointer-events: auto;
} /* 默认:响应事件 */
.non-clickable {
pointer-events: none;
} /* 不响应事件,事件穿透 */

实用场景#

/* 禁用按钮但保持样式 */
.button-disabled {
pointer-events: none;
opacity: 0.5;
}
/* 遮罩层允许点击穿透 */
.overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
pointer-events: none; /* 遮罩不阻挡点击 */
}
.overlay .modal {
pointer-events: auto; /* 弹窗可点击 */
}
/* 装饰元素不阻挡交互 */
.decoration {
position: absolute;
pointer-events: none;
}
/* 加载中禁止交互 */
.loading {
pointer-events: none;
opacity: 0.7;
}

SVG 专用值#

.svg-element {
pointer-events: fill; /* 只响应填充区域 */
pointer-events: stroke; /* 只响应描边 */
pointer-events: visible; /* 可见部分响应 */
pointer-events: painted; /* 填充和描边响应 */
}

user-select 文本选择#

控制用户是否可以选择文本:

.selectable {
user-select: auto;
} /* 默认 */
.select-all {
user-select: all;
} /* 点击全选 */
.select-text {
user-select: text;
} /* 可选文本 */
.no-select {
user-select: none;
} /* 禁止选择 */
.select-contain {
user-select: contain;
} /* 选择限制在元素内 */

实用场景#

/* 按钮文字不可选 */
button {
user-select: none;
}
/* 代码块点击全选 */
.code-block {
user-select: all;
}
/* 图标不可选 */
.icon {
user-select: none;
}
/* 可复制的重要信息 */
.copyable {
user-select: all;
background: #f3f4f6;
padding: 8px 12px;
border-radius: 4px;
cursor: pointer;
}
/* 防止拖拽时选中文字 */
.draggable-area {
user-select: none;
}

resize 可调整大小#

允许用户调整元素大小:

.resize-both {
resize: both;
overflow: auto; /* 必须 */
}
.resize-horizontal {
resize: horizontal;
overflow: auto;
}
.resize-vertical {
resize: vertical;
overflow: auto;
}
.no-resize {
resize: none;
}

文本框调整#

/* 只允许垂直调整 */
textarea {
resize: vertical;
min-height: 100px;
max-height: 500px;
}
/* 禁止调整 */
textarea.fixed {
resize: none;
}
/* 自由调整 */
.resizable-box {
resize: both;
overflow: auto;
min-width: 200px;
min-height: 100px;
max-width: 100%;
border: 1px solid #d1d5db;
padding: 16px;
}

touch-action 触摸操作#

控制元素的触摸行为:

.touch-auto {
touch-action: auto;
} /* 默认:允许所有 */
.touch-none {
touch-action: none;
} /* 禁止所有触摸操作 */
.pan-x {
touch-action: pan-x;
} /* 只允许水平平移 */
.pan-y {
touch-action: pan-y;
} /* 只允许垂直平移 */
.pinch-zoom {
touch-action: pinch-zoom;
} /* 只允许缩放 */
.manipulation {
touch-action: manipulation;
} /* 平移和缩放,禁止双击缩放 */

实用场景#

/* 轮播/滑块 - 只允许水平滑动 */
.carousel {
touch-action: pan-x;
overflow-x: auto;
}
/* 垂直滚动列表 - 只允许垂直 */
.vertical-list {
touch-action: pan-y;
}
/* 画布/地图 - 自定义手势处理 */
.canvas {
touch-action: none;
}
/* 按钮 - 避免双击缩放延迟 */
button {
touch-action: manipulation;
}
/* 图片画廊 - 允许缩放和平移 */
.gallery-view {
touch-action: pan-x pan-y pinch-zoom;
}

caret-color 光标颜色#

设置文本输入光标的颜色:

input {
caret-color: #3b82f6;
}
/* 透明光标(隐藏) */
.hidden-caret {
caret-color: transparent;
}
/* 继承文字颜色 */
.inherit-caret {
caret-color: auto;
}

accent-color 强调色#

设置表单控件的主题色:

:root {
accent-color: #3b82f6;
}
/* 单独设置 */
input[type='checkbox'] {
accent-color: #10b981;
}
input[type='radio'] {
accent-color: #8b5cf6;
}
input[type='range'] {
accent-color: #f59e0b;
}
progress {
accent-color: #ef4444;
}

appearance 外观#

控制元素的原生外观:

/* 移除默认样式 */
.custom-input {
appearance: none;
-webkit-appearance: none;
}
/* 常见用法 */
input[type='number'] {
appearance: textfield; /* 移除箭头 */
}
select.custom {
appearance: none;
background: url('arrow.svg') right center no-repeat;
}

自定义表单控件#

/* 自定义复选框 */
input[type='checkbox'].custom {
appearance: none;
width: 20px;
height: 20px;
border: 2px solid #d1d5db;
border-radius: 4px;
cursor: pointer;
}
input[type='checkbox'].custom:checked {
background: #3b82f6;
border-color: #3b82f6;
}
input[type='checkbox'].custom:checked::after {
content: '';
color: white;
display: flex;
justify-content: center;
align-items: center;
}
/* 自定义单选框 */
input[type='radio'].custom {
appearance: none;
width: 20px;
height: 20px;
border: 2px solid #d1d5db;
border-radius: 50%;
cursor: pointer;
}
input[type='radio'].custom:checked {
border-color: #3b82f6;
background: radial-gradient(#3b82f6 50%, transparent 50%);
}

可访问性媒体查询#

prefers-reduced-motion#

尊重用户的动画偏好:

/* 默认有动画 */
.animated {
transition: transform 0.3s ease;
}
.animated:hover {
transform: scale(1.05);
}
/* 用户偏好减少动画 */
@media (prefers-reduced-motion: reduce) {
.animated {
transition: none;
}
.animated:hover {
transform: none;
}
/* 全局禁用动画 */
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}

prefers-color-scheme#

响应系统主题:

:root {
--bg: white;
--text: #1f2937;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1f2937;
--text: #f9fafb;
}
}
body {
background: var(--bg);
color: var(--text);
}

prefers-contrast#

响应对比度偏好:

@media (prefers-contrast: more) {
:root {
--border-color: black;
--text-muted: #1f2937;
}
button {
border: 2px solid black;
}
}
@media (prefers-contrast: less) {
:root {
--border-color: #e5e7eb;
--text-muted: #9ca3af;
}
}

实战案例#

可拖拽卡片#

.draggable-card {
cursor: grab;
user-select: none;
touch-action: none;
transition:
box-shadow 0.2s,
transform 0.2s;
}
.draggable-card:active {
cursor: grabbing;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
transform: scale(1.02);
}
.draggable-card.dragging {
opacity: 0.8;
pointer-events: none;
}

图片查看器#

.image-viewer {
touch-action: pinch-zoom pan-x pan-y;
cursor: zoom-in;
user-select: none;
}
.image-viewer.zoomed {
cursor: zoom-out;
}
.image-viewer.panning {
cursor: grabbing;
}

代码复制按钮#

.code-wrapper {
position: relative;
}
.code-block {
user-select: all;
padding: 16px;
background: #1f2937;
border-radius: 8px;
overflow-x: auto;
}
.copy-button {
position: absolute;
top: 8px;
right: 8px;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s;
}
.code-wrapper:hover .copy-button {
opacity: 1;
}

禁用状态表单#

fieldset:disabled {
pointer-events: none;
opacity: 0.6;
}
fieldset:disabled * {
cursor: not-allowed;
}
.form-loading {
position: relative;
pointer-events: none;
}
.form-loading::after {
content: '';
position: absolute;
inset: 0;
background: rgba(255, 255, 255, 0.7);
cursor: wait;
}

滑块组件#

.slider {
touch-action: pan-x;
user-select: none;
cursor: pointer;
}
.slider-thumb {
cursor: grab;
}
.slider-thumb:active {
cursor: grabbing;
}
.slider-track {
pointer-events: none;
}

响应式可访问设计#

/* 基础样式 */
.card {
transition:
transform 0.3s,
box-shadow 0.3s;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}
/* 减少动画 */
@media (prefers-reduced-motion: reduce) {
.card {
transition: none;
}
.card:hover {
transform: none;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
}
/* 高对比度 */
@media (prefers-contrast: more) {
.card {
border: 2px solid currentColor;
}
.card:hover {
outline: 3px solid currentColor;
}
}

常见问题#

🤔 pointer-events: none 后子元素也无法点击?

子元素需要单独设置 pointer-events: auto

🤔 touch-action 设置后滚动不正常?

确保设置正确的值,pan-y 允许垂直滚动,pan-x 允许水平滚动。

🤔 cursor 自定义图片不显示?


CSS 用户交互属性直接影响用户体验。合理使用这些属性,可以让你的界面更加友好、直观,同时也要注意可访问性,尊重用户的系统偏好设置。

至此,CSS 系列 25 篇文章全部完成!从选择器基础到现代布局,从动画效果到用户交互,希望这个系列能帮助你全面掌握 CSS 技术。