纯 css 无法真正读取鼠标坐标,必须借助少量 js 动态设置 css 自定义属性(如 --tx/--ty),再通过 transform: translate(calc(var(--tx) 1px), calc(var(--ty) 1px)) 实现瞳孔偏移;需限制偏移范围(如 ±6px)、容器设 overflow: hidden,并配合 animation-fill-mode: forwards 实现自然眨眼。

怎么用 transform + animation 让眼睛“看”鼠标方向
纯 CSS 实现眼睛跟随鼠标,本质不是真的追踪坐标,而是利用视差错觉:固定眼白,让瞳孔在有限范围内偏移。关键在于把 transform: translate() 的值和鼠标位置做映射,但 CSS 本身不能读取鼠标坐标——所以必须靠少量 JS 控制 class 或自定义属性。
- 真实项目中,直接写
transform: translate(2px, -3px)是静态的;要动态,得用 JS 更新style="--tx: 2; --ty: -3;",再在 CSS 里写transform: translate(calc(var(--tx) <em> 1px), calc(var(--ty) </em> 1px)); - 不要用
left/top动画,重排开销大,容易掉帧 - 瞳孔容器必须设
overflow: hidden,否则偏移出眼白边界会露馅 - 建议限制最大偏移量(比如 ±6px),否则像斗鸡眼或翻白眼,破坏真实感
@keyframes 眨眼动画为什么总卡在半途?
常见错误是把 animation-fill-mode 漏掉或设成 none,导致动画一播完就跳回初始状态,眼皮“弹开”感极强。
- 正确写法是加
animation-fill-mode: forwards;,让最后一帧样式保留 - 如果想实现自然间隔眨眼(比如每 3–5 秒随机一次),别用固定
animation-delay,改用多个不同周期的动画叠加,或 JS 动态切换 class 触发 - 注意上下眼睑要错开时间:上眼睑
animation: blink 0.3s,下眼睑加animation-delay: 0.15s,才像肌肉协同运动 - 避免在
blink动画里同时改height和opacity:浏览器可能不同步渲染,造成撕裂感;优先用transform: scaleY()+transform-origin: top
用 box-shadow 画瞳孔比用 div 更省 DOM 吗?
是,但有硬约束:只能做单色、无渐变、边缘模糊可控的简单瞳孔。比如 box-shadow: 2px 2px 0 0 #000; 可以快速生成一个偏移黑点,适合低配设备或极简 UI。
- 优势:零额外 HTML 元素,CSS 单行控制位移,动画触发快
- 劣势:无法做径向渐变高光、无法独立设置 border-radius、不支持伪类动画(
::before能用,但box-shadow本身不能被 keyframes 单独驱动) - 实测发现:Chrome 中连续修改
box-shadow的偏移值,帧率比操作transform低 10% 左右,尤其在低端安卓 WebView 里容易卡顿 - 如果需要虹膜纹理或缩放效果(比如受惊时瞳孔放大),必须用嵌套
div+transform: scale()
为什么左右眼动画不同步会导致“精神分裂感”?
人眼眨眼本就是异步的,但异步 ≠ 随机乱动。真实眨眼有 0.1–0.3 秒的上下睑启动差、左右眼间隔通常 animation-delay: 1s、右眼设2s,就会形成明显“轮流眨”,观感诡异。
- 解决方法:用同一个
@keyframes,但左右眼分别加微小 delay(如0.02s和0.05s),或者 JS 随机生成delay在 ±30ms 范围内 - 更稳妥的做法是只动一只眼做 wink,另一只保持静止——这是最不容易翻车的拟人化策略
- 所有眼部动画的
animation-timing-function必须用cubic-bezier(0.34, 1.56, 0.64, 1)这类非对称缓动,模拟眼皮肌肉的加速-减速特性;线性(linear)看起来像机械臂
真实项目里最容易被忽略的,是眼眶的轻微呼吸式缩放(transform: scale(0.995) 循环)——它不抢戏,但能让整套动画从“动图”升级为“活物”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











