微信摇一摇动效需模拟真实手部晃动:采用非对称旋转(-3deg→4deg→-1deg)、±1%缩放、0.4s ease-out时长、transform-origin偏移至握持点,并由JS通过devicemotion事件触发防误触。

用 @keyframes 模拟摇晃的物理感,不是单纯左右平移
微信摇一摇的动效核心是「短时高频+轻微旋转+轻微缩放」,不是匀速 translateX 来回拉。直接写 0% { transform: rotate(0); } 50% { transform: rotate(5deg); } 100% { transform: rotate(0); } 会显得生硬——人手晃手机时,是轴心不稳、角度不对称、末尾还有微顿感。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 用
rotate(-3deg)→rotate(4deg)→rotate(-1deg)模拟非对称抖动,避免镜像对称的机械感 - 叠加
scale(0.99)到scale(1.01),幅度控制在 ±1%,否则像弹跳而非晃动 - 动画时长设为
0.4s,ease-out收尾,模仿肌肉释放后的自然衰减 - 别用
infinite循环——真实摇一摇是一次性动作,触发后应靠 JS 控制播放次数
用 transform-origin 锚定晃动中心点
默认 transform-origin: center 会让元素绕自身中心转,但手机被握持时,晃动其实是绕手掌虎口附近的小区域发生的。视觉上更可信的做法是把旋转原点偏移到左下或右下角(模拟握持点)。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 对容器加
transform-origin: 20% 80%(左下偏内),再配合rotate,晃动感立刻更“沉” - 如果元素本身有阴影或边框,偏移原点后阴影位置会突兀,需同步用
filter: drop-shadow()替代box-shadow,避免投影随 transform 变形 - 移动端 Safari 对非
center的transform-origin在某些 zoom 场景下有渲染毛刺,可加will-change: transform预提升图层
用 JS 触发并防重复播放
CSS 动画本身不能监听设备运动,所谓“摇一摇”必须由 JS 检测 devicemotion 事件后手动触发 class 切换。很多人卡在「一摇就狂播」「停不下来」「iOS 不响应」。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 监听
accelerationIncludingGravity的x/y值,取绝对值后加权求和:Math.abs(x) + Math.abs(y) * 0.7(y 轴受重力干扰大,要降权) - 设阈值
12(单位 m/s²),连续 2 帧超阈值才判定为有效摇动,避免误触 - 触发后立即
element.classList.add('shake'),并在animationend事件里remove,禁止用setTimeout移除——动画可能被系统节流打断 - iOS Safari 默认禁用
devicemotion,需用户首次触摸后才能启用,加一句document.body.addEventListener('touchstart', enableMotion, { once: true })
兼容性与性能关键点
这个动效在低端安卓机上容易掉帧,尤其同时跑多个 transform 属性时。别迷信「硬件加速」,translateZ(0) 在部分 Android WebView 里反而引发闪烁。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 只对
transform和opacity做动画,杜绝left/top或margin——这些会触发重排 - 动画元素层级要独立,加
isolation: isolate防止父容器filter或backdrop-filter拖慢子动画 - Android Chrome 115+ 对
devicemotion采样率大幅降低,默认 60fps 变成 15fps,检测逻辑要适应低频数据,别依赖「快速连续变化」 - 真机调试时,Safari 开发者工具的「Timelines」面板比 Chrome 的 Performance 更准,能看清 Core Animation 提交是否卡顿
真正难的不是写出晃动,而是让每次晃动都像人手真实发出的——力度有随机性、结束有余震、中间无规律停顿。这些细节得靠 JS 控制动画参数动态生成,而不是写死一套 keyframes。



















