index.html如何实现页面加载时的淡入效果?并不只看表面做法,关键还要理解相关条件、限制和后续影响。
最轻量解法是body初始opacity:0并设transition,DOMContentLoaded时加loaded类实现淡入;须避免display:none导致重排,用opacity+visibility组合;配合font-display:swap防字体闪白;Safari需用包裹div替代body。
页面一打开就全白闪一下再显示,是因为浏览器默认立刻渲染 DOM,没给视觉过渡留时间。最轻量的解法是让 <body> 或根容器初始为 opacity: 0,加载完成后再切到 1,配合 transition 实现淡入。
关键点在于:必须在样式表里提前写好初始状态和过渡规则,不能等 JS 加载完才加 class,否则首屏仍会“硬出现”。
<head> 的 <style> 或外链 CSS 中定义:body { opacity: 0; transition: opacity 0.4s ease-out;}body.loaded { opacity: 1;}
</body> 前,用 DOMContentLoaded 触发(不是 load,避免等图片):document.addEventListener('DOMContentLoaded', () => { document.body.classList.add('loaded');});
DOMContentLoaded 可能延迟,此时淡入会滞后——建议把该逻辑抽成最小化内联 script,不依赖外部 bundle有人习惯用 display: none 配合 JS 切成 block 来“隐藏再显示”,这会导致浏览器跳过首次布局计算,后续显示时重排(reflow),尤其在字体加载、图片尺寸未定的情况下,页面可能先塌缩再撑开,破坏淡入体验。
opacity + visibility 组合替代 display 切换:body { opacity: 0; visibility: hidden; /* 防止点击/聚焦 */ transition: opacity 0.4s ease-out;}body.loaded { opacity: 1; visibility: visible;}
visibility: hidden 不触发重排,且保持文档流位置,比 display: none 更安全position: fixed 元素(如导航栏),它们不受 body 的 visibility 影响,需单独加类控制即使 DOM 渲染淡入了,如果 Web 字体还没加载完成,浏览器会先用系统字体渲染,等字体就绪后突然替换,造成文字大小/行高变化,看起来像二次闪烁。这不是淡入失效,而是字体加载时机问题。
@font-face 的 font-display: swap 让浏览器立即用后备字体显示,等自定义字体加载完再无感替换:@font-face { font-family: 'MyFont'; src: url('myfont.woff2') format('woff2'); font-display: swap;}
document.fonts.load(),等关键字体就绪后再加 loaded 类,但需考虑超时兜底(比如 3s 后强制淡入,避免用户干等)&display=swap 参数,例如:https://fonts.googleapis.com/css2?family=Inter&display=swap
iOS 15.4 之前,Safari 对 body 上的 transition 支持不稳定,有时直接跳变。这不是 bug,而是它对根元素动画做了优化限制。
<body>,改用包裹一层 <div id="app">,把 opacity 和 transition 移到这个 div 上height: 100vh,否则在 Safari 中可能出现滚动条异常或底部留白body
实际效果是否平滑,取决于你是否把动画属性写在 CSS 里、是否避开重排、以及是否处理了字体和移动端的特殊限制。最容易被忽略的是:把淡入逻辑绑在 window.onload 上——这时图片、字体、第三方脚本都可能还没完,用户已经看到白屏好几秒了。