加 body { background-color: #f8f9fa } 能压住第一帧白屏,是因为它在 HTML 的 <head> 内联 <style> 中声明,使浏览器在 CSSOM 构建前即用该 solid 颜色绘制首帧,避免默认白色背景;但仅此不足以解决文字错位、布局跳动等 FOUC 问题。

首屏留白不是列表没加载完,而是浏览器在等关键样式就绪前,用默认白色背景画了一帧——这帧里什么都没有,就显白。
为什么加 body { background-color: #f8f9fa } 能压住第一帧白屏
移动端刷新时,HTML 已开始解析,但外部 CSS 还没下载完、CSSOM 没构建好,浏览器只能拿 body 的默认背景(透明或白色)去绘制首帧。只要在 <head> 里内联一行纯色背景,这一帧就有内容可画:
- 必须写在
<style>块中,不能靠外部 CSS 文件 - 颜色值要简单:只用
#hex或rgb(),禁用url()、渐变、CSS 变量 - 选页面主色调最接近的 solid 颜色,比如浅灰
#f8f9fa比纯黑#000更自然 - 单靠这个只能压白,文字错位、布局跳动等 FOUC 依然存在
怎么提取并内联“首屏关键 CSS”
真正要内联的,是影响视口内所有可见节点的最小样式集:比如列表容器 .list 的 display: grid、首屏项 .item:first-child 的 height 和 background、标题 .item-title 的 font-size 和 line-height。
- 工具推荐:
criticalCLI(支持 HTML 输入 + viewport 尺寸指定),或手动梳理后注入模板 - 体积控制在 ≤14KB,否则 HTML 解析反而变慢
- 禁用
@import和url(...),它们会让内联样式延迟生效甚至失效 - 验证方式:DevTools → Network → Offline,刷新——首屏结构和文字是否仍清晰?
为什么 JS 主题切换会让首屏再闪一次
很多项目在 DOMContentLoaded 后读取 localStorage 切 dark mode,结果 DOM 渲染完才加 dark class,导致先闪一次浅色再跳深色——比白屏更刺眼。
立即学习“前端免费学习笔记(深入)”;
- 把主题 class 直接写死在
<html class="light">或服务端输出时决定 - 若必须 JS 控制,用
<style media="print">占位,加载完成后移除media并注入对应样式 - 避免在 JS 中操作
document.documentElement.classList太晚,首帧早已完成 - 检查 styled-components 等库是否动态注入样式,它们会绕过内联逻辑,造成二次重绘
复杂点在于:留白从来不是单一 CSS 规则能解决的问题,而是 HTML 解析顺序、CSS 加载时机、JS 执行节奏、服务端输出策略共同作用的结果。最容易被忽略的是——你写的那行 background-color,如果放在外部 CSS 里,它就根本来不及参与首帧绘制。


















