齿轮转动需实时响应滚轮方向:监听 wheel 事件,依 deltaY 正负增减旋转角度并硬设 transform,禁用 transition 以避免滞后;deltaY > 0 时顺时针转,角度取模归一化,确保丝滑跟手。

用 transform: rotate() 配合 wheel 事件监听滚动方向
齿轮转动不是靠 CSS 动画循环,而是实时响应滚轮方向做增量旋转。核心是监听 wheel 事件,根据 event.deltaY 正负判断滚动方向,再动态更新元素的 rotate() 值。
注意:不能直接用 transition 过渡 rotate(),否则会插值平滑掉“跟随感”,导致转动滞后或反向回弹。必须用 transform: rotate(${angle}deg) 硬设当前角度。
-
deltaY > 0表示向下滚动(惯性滚动也适用),应顺时针转(角度+) deltaY 表示向上滚动,应逆时针转(角度−)- 每次变化量建议控制在
1.5–3deg区间,太小不明显,太大显生硬 - 记得用
event.preventDefault()阻止默认滚动(如果齿轮是独立容器且不需要页面滚动)
避免 transform 累积误差和数值溢出
持续累加 angle 变量会导致数字越来越大(比如转到 12487deg),虽不影响视觉,但可能引发浮点精度偏差或某些浏览器渲染异常。更稳妥的做法是模 360:
angle = (angle + delta) % 360;
但注意:JavaScript 的 % 对负数结果不符合数学模运算(如 -5 % 360 === -5),所以推荐用函数归一化:
function normalizeAngle(a) { return ((a % 360) + 360) % 360; }
- 每次更新后调用
normalizeAngle(angle),确保角度始终落在[0, 360) - CSS 中仍写
rotate(123.4deg),不用强制转整数,小数角度完全支持 - 不要用
getComputedStyle(el).transform反查当前角度——解析矩阵成本高且不可靠
齿轮 SVG 或伪元素需启用 will-change: transform
高频更新 transform 时,不加优化容易掉帧,尤其在低端设备上。对齿轮容器加这一行能提示浏览器提前升层:
.gear { will-change: transform; }
但别滥用:只加在真正被频繁 transform 的元素上;若齿轮是 内的 或 ,要加在该 SVG 元素或其父容器上。
- 不加
will-change在多数现代浏览器里也能跑,但快速连续滚轮时可能出现卡顿 - 避免同时对同一元素设置
will-change: transform和opacity,会触发多余合成层 - Chrome DevTools 的 “Rendering” 面板勾选 “Paint flashing” 可验证是否触发了重绘
兼容性与 touchpad 滚动细节
Mac 触控板默认触发的是带惯性的 wheel 事件,deltaY 值比鼠标滚轮大得多,一次轻扫可能达 ±50+。直接按原值累加会导致齿轮“嗖”一下转好几圈。
- 对触控板做降频处理:用
requestAnimationFrame节流,或简单除以10(deltaY / 10)再累加 - 区分设备类型不现实,统一用
Math.sign(deltaY) * Math.min(2.5, Math.abs(deltaY) * 0.1)更稳 - Firefox 对
wheel事件的deltaMode可能为DOM_DELTA_LINE,但现代 CSS 滚动已基本统一用像素单位 - 移动端 Safari 不支持在非滚动容器内阻止
wheel默认行为,如有需要得配合touchmove+preventDefault
实际角度更新逻辑最简示例:
let angle = 0;
gearEl.addEventListener('wheel', e => {
e.preventDefault();
angle += e.deltaY > 0 ? 2 : -2;
angle = ((angle % 360) + 360) % 360;
gearEl.style.transform = `rotate(${angle}deg)`;
});
齿轮本身用纯 CSS 边框画、SVG 或图片都行,关键在 transform 控制权必须完全交给 JS。真正在意丝滑感的人,最后都会发现:不是转得越快越好,而是每一度变化都得跟上手指的节奏。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











