卡片堆叠滑动本质是用 transform: translateX() 实现高性能偏移,每张卡叠加索引位移;需禁用默认滚动、用弹簧物理回弹,并添加 will-change 和 backface-visibility 修复 iOS 渲染问题。

用 transform: translateX() 控制卡片偏移量
卡片堆叠滑动的本质,是让每张卡片相对于上一张有固定水平位移(比如 -20px),同时整体随手指拖拽实时偏移。不能靠 left 或 margin-left,因为它们会触发重排,卡顿明显;transform: translateX() 走合成层,性能好得多。
关键点在于:所有卡片共享同一个基准偏移值(比如叫 dragOffset),再按索引叠加层级偏移:
card.style.transform = `translateX(${dragOffset + index * -20}px)`这样既保持堆叠顺序,又确保整组卡片同步响应手势。
监听 touchstart/touchmove 时禁用默认滚动
在移动端,手指在容器内滑动默认会触发页面滚动,直接抢走事件,导致卡片无响应。必须在 touchstart 阶段调用 event.preventDefault(),但只对目标容器生效,避免影响页面其他区域。
立即学习“前端免费学习笔记(深入)”;
常见错误是全局阻止或只在 touchmove 阻止——太晚,系统可能已判定为滚动手势:
- 给卡片容器加
touch-action: none(CSS 层面更稳妥) -
touchstart回调里立刻event.preventDefault() - 别忘了绑定
touchend和touchcancel来清理状态
松手后用 spring physics 做回弹或吸附
纯跟随手势只是基础,用户真正需要的是“松手后自动滑到最近卡片位置”或“超出阈值就翻页”。硬编码 setTimeout + transition 不够自然,建议用轻量物理模型模拟阻尼弹簧效果。
核心是根据松手瞬间的 velocity(速度)和剩余位移,动态计算目标位置和动画时长:
const targetX = Math.round(dragOffset / CARD_WIDTH) * CARD_WIDTH;
再用 requestAnimationFrame 逐帧更新 transform,比 CSS transition 更可控,也更容易中断(比如用户中途又拖了)。
兼容 iOS Safari 的 will-change 和 backface-visibility
iOS Safari 对 transform 动画有渲染优化缺陷:快速滑动时卡片边缘可能闪烁或出现锯齿。这不是 bug,是 WebKit 合成策略导致的。
两个低成本修复项必须加:
- 卡片元素加
style.willChange = 'transform'(仅在拖拽中设置,避免常驻开销) - 卡片加
backface-visibility: hidden(CSS 中写死,防 3D 反转抖动) - 别用
transform: translateZ(0)强升层——iOS 16+ 已不推荐,反而增加内存压力
这些细节不显眼,但缺一不可;尤其在 iPhone 上,少一个都可能让动效从流畅变成幻灯片。


















