FOUC 无样式闪烁及其避免
理解 FOUC 产生的原因及解决方案
问题
什么是 FOUC(Flash of Unstyled Content),为什么会产生,如何避免?
解答
什么是 FOUC
FOUC(Flash of Unstyled Content)指页面加载时,HTML 内容先于 CSS 渲染,导致用户短暂看到无样式的页面,随后样式加载完成页面突然”闪烁”变化。
产生原因
- CSS 放在页面底部:浏览器先渲染 HTML,后加载 CSS
- 使用 @import:@import 是串行加载,会延迟 CSS 解析
- JS 动态加载样式:样式在 JS 执行后才生效
- 外部 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>
4. 避免 @import,使用 link 标签
<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预加载关键资源,提升加载优先级
目录