要实现真实3D翻页效果,需在翻页容器(如.book)设置transform-style: preserve-3d和perspective,并正确配置transform-origin、rotateY、伪元素阴影折痕及移动端touch事件优化。

用 transform-style: preserve-3d 激活真正的 3D 空间
不加这句,所有子元素会扁平渲染,翻页动画只会是“假 3D”——看起来像在转,实际只是二维缩放或倾斜。它必须设在翻页容器(比如 .book)上,且父级不能有 overflow: hidden 或 filter,否则会强制创建新的层叠上下文,切断 3D 渲染链。
常见错误:把 preserve-3d 加在页面根元素或 body 上,结果没效果。它只对直接子元素生效,且子元素自身也得有 3D 变换(比如 rotateY)才看得见立体感。
.book { transform-style: preserve-3d; perspective: 2000px; }- perspective 值越小,翻页“弧度”越夸张;太大则像在远处看纸片,缺乏厚度感
- 避免在翻页容器上同时使用
backface-visibility: hidden—— 它会让背面页完全消失,而不是自然翻转露出背面内容
用 rotateY + transform-origin 控制翻页轴心
书页绕 Y 轴旋转才是真实翻页感。关键不是角度本身,而是旋转原点是否贴合书脊边缘。默认 transform-origin: center 会让整页绕中心转,像扇子一样张开,不是“从左边掀起来”的效果。
正确做法是把左页的 transform-origin 设为 left center,右页设为 right center,再配合 rotateY(±angle) 实现单侧翻动。
立即学习“前端免费学习笔记(深入)”;
- 左页翻动:
transform: rotateY(-60deg); transform-origin: left center; - 右页翻动:
transform: rotateY(60deg); transform-origin: right center; - 角度超过 90deg 后,需手动切换
z-index层级,否则新页会被旧页遮挡 - 不要用
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)这类“过冲”贝塞尔曲线——翻页是阻尼运动,推荐cubic-bezier(0.25, 0.46, 0.45, 0.94)
用伪元素 ::before 模拟纸张阴影与折痕
CSS 无法生成真实光照模型,但可以用叠加层伪造体积感。核心是两层:一层浅灰渐变模拟纸张受光面,一层深色细条模拟书页弯折处的暗线。
阴影不能靠 box-shadow,它会随旋转失真;必须用绝对定位的伪元素,随翻页角度动态调整 opacity 和 transform。
- 左页翻起时,在其右侧加
::before,background: linear-gradient(90deg, transparent, rgba(0,0,0,0.15), transparent) - 折痕线用
height: 2px; background: #ccc; transform: scaleY(0.6) translateZ(1px),确保它始终“压”在翻页交界处 - 所有伪元素必须设
pointer-events: none,否则会拦截点击事件,导致翻页按钮失效
移动端 touch 事件与 will-change 的取舍
在 iOS Safari 上,单纯靠 hover 触发翻页几乎不可用;必须绑定 touchstart/touchmove 手动计算拖拽距离映射到 rotateY 角度。但频繁改写 transform 会导致卡顿,尤其老设备。
will-change: transform 能提前触发 GPU 加速,但它会持续占用显存。如果页面还有其他动画(比如滚动视差),加了反而更慢。
- 只对正在翻页的单个
.page元素动态添加will-change,翻完立刻移除 - 用
requestAnimationFrame绑定 touchmove,避免连续触发重排 - iOS 上
transform: rotateY在 0deg 和 180deg 附近容易抖动,建议限制最大角度为175deg,留 5deg 缓冲
翻页动画真正难的不是转几度,而是让每一页的厚度、阴影、层级、触控响应在不同设备上都保持一致——这些细节没有标准解法,只能靠真机反复调参数。


















