cursor 不支持 CSS transition——因其为离散状态,无中间值可插值;可通过隐藏原生光标、用绝对定位元素模拟并绑定 JS 状态切换实现视觉过渡效果。

transition 无法直接作用于 cursor
CSS 的 transition 属性对 cursor **完全无效**——无论你写 transition: cursor 0.3s 还是 all 0.3s,浏览器都会静默忽略。这不是兼容性问题,而是规范明确不支持:cursor 是离散状态(pointer、text、not-allowed 等),没有中间值可插值,过渡引擎无从下手。
实现“视觉上”的 cursor 动态变化效果
虽然不能真过渡 cursor,但可以通过覆盖层 + 动画模拟出类似体验。核心思路是:隐藏原生光标,用绝对定位的自定义元素(如 )跟随鼠标移动,并在状态切换时触发动画。
真实项目中,cursor 状态往往取决于元素语义(按钮禁用、文本可选、拖拽区域等)。不要靠全局 自定义光标在触摸设备上毫无意义(无 hover、无 cursor 概念),且会破坏屏幕阅读器的焦点指示。上线前务必加检测:
立即学习“前端免费学习笔记(深入)”; 最易被忽略的是:自定义光标元素若未设置
body { cursor: none; }
pointer-events: none 避免干扰交互data-state 属性,再用 CSS 控制其缩放/颜色/尺寸动画transform 触发重排body {
cursor: none;
}
.custom-cursor {
position: fixed;
width: 24px;
height: 24px;
border-radius: 50%;
background: #3b82f6;
transform: translate(-50%, -50%);
pointer-events: none;
z-index: 9999;
transition: transform 0.2s, background 0.2s;
}
.custom-cursor[data-state="hover"] {
transform: translate(-50%, -50%) scale(1.4);
background: #ef4444;
}
.custom-cursor[data-state="text"] {
width: 32px;
height: 16px;
background: #10b981;
border-radius: 2px;
}
cursor 变化时机与 JS 绑定策略
mouseenter 盲切,应结合具体场景精准控制:
button[disabled] 或 [aria-disabled="true"],统一设为 not-allowed
input[type="text"]、textarea、带 contenteditable 的元素,进入时设 text
[draggable="true"])时,设 grab;拖拽中改 grabbing
mousemove,优先用事件委托到父级移动端与无障碍的取舍提醒
matchMedia('(hover: hover) and (pointer: fine)') 判断是否支持悬停prefers-reduced-motion: reduce 下应禁用所有光标动画aria-hidden="true",可能被读屏器误读为页面内容。这点常被跳过,但直接影响无障碍合规性。

