效果演示

文末可一键复制完整代码
源代码
<!DOCTYPE html><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>翻页倒计时</title><style> *{box-sizing:border-box;margin:0;padding:0}html,body{width:100%;height:100%;overflow:hidden;margin:0}body{min-height:100dvh;min-width:100vw;display:flex;flex-direction:column;background:#0a0a0a}.stage{flex:1;position:relative;width:100%;height:100%;min-height:0;overflow:hidden}.stagecanvas,.stagesvg{width:100%;height:100%;display:block}.stage--center{display:grid;place-items:center;background:#111}.unit{position:relative;width:min(32vmin,240px);aspect-ratio:11 / 13;perspective:min(140vmin,900px);font:800clamp(2.5rem,11vmin,5.5rem)/1"Segoe UI",sans-serif;color:#eee}.half{position:absolute;left:0;right:0;height:50%;overflow:hidden;background:#2a2a2a;border:1px solid #555;display:grid;place-items:center;backface-visibility:hidden}.top,.flip-top{top:0;border-radius:0.22em0.22em00;align-items:end;padding-bottom:0.04em;transform-origin:bottom}.bot,.flip-bot{bottom:0;border-radius:000.22em0.22em;align-items:start;padding-top:0.04em}.flip-top{transition:transform 0.45s;transform:rotateX(0deg)}.flip-bot{transform:rotateX(90deg);transition:transform 0.45s}.unit.anim.flip-top{transform:rotateX(-90deg)}.unit.anim.flip-bot{transform:rotateX(0deg)}</style></head><body><divclass="stage stage--center"><divclass="unit"id="u"><divclass="half top"id="top">30</div><divclass="half bot"id="bot">30</div><divclass="half flip-top"id="ft">30</div><divclass="half flip-bot"id="fb">29</div></div></div><script> (() => { let n = 30; const u = document.getElementById('u'); const top = document.getElementById('top'); const bot = document.getElementById('bot'); const ft = document.getElementById('ft'); const fb = document.getElementById('fb'); functionshow(v) { const s = String(v).padStart(2, '0'); top.textContent = ft.textContent = s; bot.textContent = fb.textContent = s; } show(n); setInterval(() => { if (n <= 0) return; const next = n - 1; fb.textContent = String(next).padStart(2, '0'); u.classList.add('anim'); setTimeout(() => { n = next; show(n); u.classList.remove('anim'); }, 450); }, 1000); })();</script></body></html>实现思路拆分
翻页倒计时是怎么做出来的?
这一篇做一个翻页倒计时:数字拆成上下半片,每秒沿 X 轴翻页切换,像机场翻牌钟。整页靠 HTML、CSS 与 JavaScript 完成。
整体思路:三块内容分工
可以把成品页面想成三块积木拼在一起:
结构:全视口 .stage+ 四片半屏数字层(上静止、下静止、翻页上、翻页下)。动效: perspective与rotateX做翻牌;.unit.anim时上半翻出、下半翻入。脚本: setInterval每秒写入下一数字、加.anim,450ms 后同步四片文字并移除动画类。
结构和样式分开写,改布局与动效时各动各的;逻辑集中在脚本,便于调整节奏与交互。
配色与场景氛围
这一版用颜色与背景营造场景,而不只是装饰:
让画面「活」起来
Grid place-items: center 让主体在视口正中。全视口 .stage 占满剩余高度,无额外标题栏。min() / clamp() / vmin 让组件随屏幕等比放大缩小。perspective + rotateX 做翻页式 3D 翻转。
动效方面,这一版启用了这些效果:
.anim类触发翻页/过渡动画,结束后由脚本移除setInterval驱动定时刷新(如倒计时每秒翻页)脚本切换 class(如 .anim、.open)配合 CSS 过渡transition让状态切换更顺滑
结构拆解:从上到下的图层
页面骨架
全视口 .stage容器承载效果无标题 UI,打开即是演示本身
主要结构与图层
.stage:全视口舞台容器,承载整块效果.unit:倒计时翻牌单元,内含四片半屏数字.half:上半片或下半片数字,各显示两位数字的一部分
翻页时序
每秒: fb先写入下一秒的个位数,再给.unit加.anim.flip-top从 0° 翻到 -90°,.flip-bot从 90° 翻到 0°,过渡约 450ms动画结束后四片文字统一为新值,并移除 .anim,等待下一秒
源码获取

夜雨聆风