纯CSS 3D翻页通过perspective+rotateY+preserve-3d实现,需精确计算点击位置、强制硬件加速、节流触摸动画并处理多端缩放适配。

用 CSS 3D 变换模拟真实翻页,别碰 jQuery 插件
纯 CSS 实现的翻页效果更轻量、可控性高,且避免了老式 turn.js 等 jQuery 插件在现代浏览器中兼容差、触摸响应卡顿、无法 SSR 的问题。核心是利用 transform: rotateY() + perspective + 正确的 transform-style: preserve-3d 组合,让左右两页形成“书本对开”视角。
常见错误是只加 rotateY 却漏掉父容器的 perspective,导致翻转扁平无纵深;或子元素未设 transform-style: preserve-3d,使翻转后内容被压平失效。
- 每页需设固定宽高与
position: absolute,左页left: 0,右页right: 0 - 翻页容器(如
.book)必须设perspective: 1500px(值越小翻转越夸张,建议 1200–2000) - 左右页自身需设
transform-style: preserve-3d,否则子元素(如文字、图片)不参与 3D 空间 - 翻页动画用
transform: rotateY(±180deg)控制,配合transition: transform 0.6s ease-out
用 getBoundingClientRect() 做精准点击翻页定位
用户点击页面右侧时翻下一页、左侧时翻上一页——不能靠简单区域判断(比如 clientX > width/2),因为页面可能缩放、滚动或有横向偏移。必须用 getBoundingClientRect() 获取当前视口内页的精确边界,再结合 event.clientX 计算相对位置。
否则在移动端双指缩放后、或桌面端 zoom: 90% 下,翻页触发区会严重偏移,点右边却翻左边。
立即学习“前端免费学习笔记(深入)”;
- 监听
click或touchend,获取事件对象event - 调用
currentPage.getBoundingClientRect()得到{ left, right, width } - 计算点击点在页内的相对横坐标:
const x = event.clientX - rect.left - 翻页阈值建议设为
rect.width * 0.3(左侧 30% 触发上翻,右侧 30% 触发下翻),留出中间 40% 防误触
处理文字重排与图像裁切:翻页时内容不能“撕裂”
翻页动画过程中,若页面内容随容器旋转而发生字体重排、行高跳变或图片被 overflow: hidden 错误裁切,会出现闪烁或白边。根本原因是浏览器对 3D 变换中的文本渲染和图层合成策略不稳定。
最有效解法是强制开启硬件加速并隔离渲染层,而非依赖 will-change 这种不可控提示。
- 给左右页加
backface-visibility: hidden,防止背面内容透出 - 给翻页容器加
transform: translateZ(0)或will-change: transform(仅用于触发 GPU 层,非动画属性) - 图片统一设
image-rendering: -webkit-optimize-contrast(Safari)和image-rendering: crisp-edges(Chrome/Firefox),减少缩放模糊 - 文字容器避免用
line-height百分比或em,改用固定px值,防止旋转时行距抖动
移动端触摸拖拽翻页:用 touchmove + requestAnimationFrame 控制帧率
直接在 touchmove 里更新 rotateY 会导致掉帧,尤其低端安卓机。必须把 DOM 更新节流到 requestAnimationFrame,且只在必要时读取触摸位移,避免频繁触发 getBoundingClientRect()。
另一个坑是未处理 touchcancel,导致手指滑出屏幕后动画卡死在半途。
- 记录
touchstart时的pageX和初始rotateY值 -
touchmove中只计算位移差,存入变量,不操作 DOM - 在
requestAnimationFrame回调里读取该位移,计算新rotateY并更新样式 - 务必监听
touchend和touchcancel,根据松手时速度决定是否补全翻页动画(用velocity * 0.5估算惯性)
翻页效果真正难的不是动效本身,而是各种缩放、滚动、多端适配下的状态一致性。比如 iOS Safari 的 viewport 缩放会重置 getBoundingClientRect() 的像素精度,这时得 fallback 到 document.documentElement.clientWidth 做比例校正。这些细节不写进逻辑,翻页就会在某个机型上突然“跳页”。



















