引导页设计:用真实信号而不是假进度条
为什么不用假进度条
很多网站的 Loading 页用假进度条:设一个 setInterval,每几十毫秒加几个百分点,跑到某个数字就跳转。问题在于:
- 跑完了资源可能还没加载好,进去后白屏
- 资源早加载好了,进度条还在慢悠悠跑到 100%,浪费时间
- 用户看到进度条到 90% 却卡住,比没有进度条更焦虑
所以换了个思路:放弃模拟,用真实的就绪信号驱动流程。
双就绪信号
这个网站首页启动需要两个资源就绪:
1. 背景视频 — 第一个视频加载到可以流畅播放
2. 音乐播放器 — window.__globalAudio(全局唯一的 audio 元素)创建完成并加载好第一首歌
SplashScreen 的进度条不是"下载百分比",而是两类就绪信号的二元组合:
bgReady: 0% → 50% // 视频 canplaythrough 触发
musicReady: 50% → 100% // audio canplaythrough 触发
每个信号只有"未就绪"和"已就绪"两种状态,没有中间值。进度条的值是:
progress = (bgReady ? 50 : 0) + (musicReady ? 50 : 0)
就四个可能值:0%, 50%, 100%——或超时直接 100%。不会有"83.7%"这种虚假精度。
超时兜底
两个信号各有一个超时分支。说到底是 Web API 的 canplaythrough 事件,偶尔会因为浏览器实现差异迟迟不触发。设 5 秒总超时——过了就强制进入,不卡用户。window.__splashSeen 标记保证再次进站跳过引导页,不需要重新加载。
为什么不用 buffered 百分比
HTMLVideoElement 有 buffered 属性,返回已缓冲的时间区间。理论上可以算百分比。实际用起来就很糟:事件稀疏,progress 事件可能一秒才触发一次,进度条跳来跳去;移动端更不稳定。canplaythrough 虽然是二元的,但足够用——用户不需要知道"缓冲到 73%"才能进去。
suppressHydrationWarning
SplashScreen 的初始状态通过内联 style 控制(防止 FOUC)。Next.js 服务端渲染时会注入这些 style,客户端 hydrate 后会根据实际的 ready 状态修改它们。因为服务端和客户端的状态差异,React 会抛 hydration mismatch 警告。加上 suppressHydrationWarning 抑制它——不是忽视问题,而是确认这个差异是设计内的。
---
引导页的核心原则:用户看到的进度必须对应真实的物理状态。做假的唯一后果是自己都没法调试——出了 bug 你不知道是真的慢还是假的慢。