FOUC 无样式闪烁及其避免

理解 FOUC 产生的原因及解决方案

问题

什么是 FOUC(Flash of Unstyled Content),为什么会产生,如何避免?

解答

什么是 FOUC

FOUC(Flash of Unstyled Content)指页面加载时,HTML 内容先于 CSS 渲染,导致用户短暂看到无样式的页面,随后样式加载完成页面突然”闪烁”变化。

产生原因

  1. CSS 放在页面底部:浏览器先渲染 HTML,后加载 CSS
  2. 使用 @import:@import 是串行加载,会延迟 CSS 解析
  3. JS 动态加载样式:样式在 JS 执行后才生效
  4. 外部 CSS 加载慢:网络延迟导致样式文件加载滞后
<!-- 错误示例:CSS 放在底部 -->
<!DOCTYPE html>
<html>
<head>
  <title>FOUC 示例</title>
</head>
<body>
  <h1>这段内容会先无样式显示</h1>
  <!-- CSS 放在底部会导致 FOUC -->
  <link rel="stylesheet" href="styles.css">
</body>
</html>
/* 错误示例:使用 @import */
/* main.css */
@import url('reset.css');  /* 串行加载,延迟渲染 */
@import url('layout.css');

解决方案

1. 将 CSS 放在 <head>

<!DOCTYPE html>
<html>
<head>
  <title>正确做法</title>
  <!-- CSS 放在 head 中,阻塞渲染直到样式加载完成 -->
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <h1>样式加载完成后才显示</h1>
</body>
</html>

2. 内联关键 CSS

<head>
  <!-- 内联首屏关键样式,避免额外请求 -->
  <style>
    body { margin: 0; font-family: sans-serif; }
    .header { background: #333; color: #fff; padding: 20px; }
    .hero { min-height: 400px; }
  </style>
  <!-- 非关键 CSS 异步加载 -->
  <link rel="preload" href="full.css" as="style" onload="this.rel='stylesheet'">
</head>

3. 使用 preload 预加载

<head>
  <!-- 预加载关键资源 -->
  <link rel="preload" href="critical.css" as="style">
  <link rel="preload" href="font.woff2" as="font" crossorigin>
  
  <link rel="stylesheet" href="critical.css">
</head>
<head>
  <!-- 并行加载多个 CSS 文件 -->
  <link rel="stylesheet" href="reset.css">
  <link rel="stylesheet" href="layout.css">
  <link rel="stylesheet" href="components.css">
</head>

5. 使用 JS 时先隐藏内容

<head>
  <style>
    /* 默认隐藏,JS 加载完成后显示 */
    .js-loading { visibility: hidden; }
  </style>
</head>
<body class="js-loading">
  <div id="app"></div>
  
  <script>
    // 应用初始化完成后移除隐藏类
    window.addEventListener('load', () => {
      document.body.classList.remove('js-loading');
    });
  </script>
</body>

关键点

  • FOUC 是 HTML 先于 CSS 渲染导致的页面闪烁现象
  • <link> 标签放在 <head> 中是最基本的解决方案
  • 避免使用 @import,它会串行加载 CSS
  • 内联关键 CSS 可消除首屏渲染的网络请求
  • 使用 preload 预加载关键资源,提升加载优先级