翻页时钟核心原理是分层遮罩与位移动画:用两块绝对定位数字面板叠加于独立.digit容器内,配合.flip-mask实现单数字翻页;需精确控制transform位移、动画时序及硬件加速。

翻页时钟的核心原理是「分层遮罩 + 位移动画」
翻页效果不是真的“翻”,而是用两块数字面板(当前值和下一位)+ 一个翻页遮罩(.flip-mask)模拟视觉切换。关键在于:每次只让一位数字动,且必须严格控制 transform: translateY() 的起止位置和过渡时序,否则会出现错位、撕裂或卡顿。
常见错误现象:overflow: hidden 没加在父容器上,导致数字滑出时露底;或者两个数字面板没用 position: absolute 叠在一起,造成文字重影。
- 每位数字必须包裹在独立的
.digit容器里,每个.digit内含两个.number-panel(当前值 / 下一值)和一个.flip-mask -
.number-panel高度设为单个数字高度的 20 倍(如数字高 40px,则面板高 800px),里面纵向排 10 个数字(0–9),用background-position-y或transform控制显示哪一行 - 翻页动画触发时,先更新下一位的
background-position-y(或transform),再对整个.digit触发transform: translateY(-40px)(即一个数字高度),持续 0.4s,ease-out
CSS 动画必须用 @keyframes 分离「翻」和「落」两阶段
直接用 transition 做翻页会丢失中间帧控制,导致翻转生硬或收不回。正确做法是定义两个关键帧动画:flip-up(向上翻出旧数字)、flip-down(向下落进新数字),再用 JS 在合适时机切换 class。
容易踩的坑:animation-fill-mode: forwards 必须加,否则动画结束后数字会弹回原位;同时要避免多个 animation 同时作用在同一个元素上,造成冲突。
立即学习“前端免费学习笔记(深入)”;
-
flip-up:从transform: translateY(0)→translateY(-40px),对应旧数字上翻消失 -
flip-down:从transform: translateY(40px)→translateY(0),对应新数字从下方顶入 - 两个动画不能同时运行,需用 JS 控制先后:先加
flippingclass 触发flip-up,动画结束(监听animationend)后再替换数字并触发flip-down
JS 更新逻辑必须按「秒→分→时」顺序逐位处理,且防抖节流
直接用 setInterval(() => new Date(), 1000) 看似简单,但实际运行中常因 JS 主线程阻塞导致跳秒。更稳的方式是每秒校准一次时间,再计算差值,只更新真正变化的位。
性能影响:如果每次都重置全部 6 个 .digit 的动画 class,会造成 layout thrashing。应只对变化的位执行翻页流程。
- 用
requestAnimationFrame驱动时间获取,比setInterval更精准 - 对比上一秒的
getSeconds()、getMinutes()、getHours(),仅对发生变化的位调用flipTo(newDigit) -
flipTo()内部先禁用动画(animation: none),强制重排,再恢复动画并添加 class,避免跳帧
移动端适配和字体渲染问题最常被忽略
在 iOS Safari 上,transform: translateY() 配合 will-change: transform 才能启用硬件加速;否则翻页会掉帧。另外,数字字体若用系统默认(如 -apple-system),不同机型渲染高度不一致,会导致翻页错位。
兼容性影响:Android 旧版 WebView 对 animation-timing-function: steps(1, end) 支持差,不能用来做“阶跃式”翻页(即不带过渡的瞬切),必须用连续 transform 动画。
- 强制指定等宽数字字体:
font-family: 'Courier New', monospace,并设line-height: 1和font-size为整数像素 - 每个
.digit加will-change: transform,且父容器设-webkit-transform: translateZ(0)激活 GPU - 避免用
%或em定义数字高度,全部用px,确保翻页位移值绝对精确
真正的难点不在“怎么动”,而在“动得准”——时间校准误差、DOM 重排时机、GPU 渲染管线同步,三者稍有错位,翻页就会抽搐或卡住。动手前先在 Chrome DevTools 的 Rendering 面板打开 “FPS Meter” 和 “Paint Flashing”,边调边看。



















