fouc不是bug,而是浏览器按规范解析html时因css加载时机不当导致的必然现象;关键样式未在html初始字节中声明、@import串行加载、media不匹配、字体或css-in-js延迟等均会触发。

HTML结构必须先于CSS加载才能避免FOUC
页面闪白(FOUC)不是浏览器bug,而是HTML解析流程决定的:如果<link rel="stylesheet">写在里,或CSS文件体积大、网络慢,浏览器会先渲染无样式的HTML,等CSS就绪再重绘。解决办法只有一个——把所有<link>放在顶部,并确保它们不带media="print"之类延迟加载的属性。
常见错误包括:用JavaScript动态插入<link>、把CSS内联在底部、或者用rel="preload"但没配as="style"和onload回填逻辑。这些都会破坏渲染流水线。
- 关键CSS(如布局、字体、按钮基础样式)必须同步加载,不能靠JS控制
- 非关键CSS(如主题色、动画、响应式断点)可用
media="(min-width: 768px)"做条件加载 - Webpack/Vite构建时,别把
css: { extract: false }设成true再塞进JS bundle——这会让CSS变成JS执行后才注入
语义化标签不是“写得像HTML5”,而是影响渲染与可访问性
用<div class="header">代替<code><header></header>,视觉上没差别,但屏幕阅读器不会宣布这是页眉,搜索引擎可能降低结构权重,甚至某些浏览器的:focus-visible聚焦逻辑会失效。语义不只是“好看”,是浏览器理解内容意图的基础。
容易被忽略的点:表单控件必须配<label for="xxx"></label>或嵌套写法;<button></button>不能用<div onclick="...">模拟;<code><main></main>只能出现一次且应包裹主体内容。
-
<article></article>适用于可独立分发的内容(博客、新闻),不是所有卡片都该用它 -
<section></section>需要有标题(<h2></h2>~<h6></h6>),否则语义断裂 - 避免嵌套
<div>超过三层——这时该考虑是否漏了<code><aside></aside>或<nav></nav>关键资源加载顺序要由HTML声明,而不是靠JS抢跑
现代打包工具喜欢把
<script></script>放底部,但若脚本依赖DOM结构(比如操作document.querySelector(".app-root")),又没加defer或type="module",就可能报Cannot read property 'xxx' of null。根源不在JS写得不好,而在HTML没明确告诉浏览器“等我画完再执行”。真正健壮的做法是:静态入口节点(如
<div id="root"></div>)必须出现在最前面;所有非阻塞脚本用defer;需要操作DOM的逻辑,统一挂到DOMContentLoaded或readyState === "interactive"事件。-
<script defer></script>比<script></script>更安全,即使放在也不会阻塞HTML解析 -
<script type="module"></script>自动defer,且支持import语法,但IE11不支持 - 不要用
document.write(),它会清空整个文档流,连里的CSS都会失效
样式隔离不是靠CSS Modules就能一劳永逸
CSS Modules只是给类名加哈希前缀,解决不了全局污染的全部问题。比如
@keyframes、@font-face、伪元素::before内容、CSS变量(--primary-color)依然全局生效。更隐蔽的问题是:两个组件同时用animation: slide-in 0.3s,哪怕类名不同,动画名冲突就会互相覆盖。真正可控的隔离需要组合策略:CSS Modules处理类名;CSS
scope(目前仅Firefox原生支持)或Shadow DOM做边界;关键动效/字体/变量用BEM命名+命名空间前缀(如myapp-slide-in)。- 第三方UI库(如Ant Design)的CSS变量尽量不直接覆盖,改用
theme配置项注入 - 使用
all: unset重置时小心——它会清掉display、font等继承属性,导致子元素完全不可见 - PostCSS插件
postcss-prefix-selector可以批量加前缀,但对@media内规则无效,需手动处理
async脚本放在里,可能让<link>的预加载失效;一个没闭合的<table>标签,会让后续所有CSS选择器匹配错乱。健壮性不是加多少层防御,而是每一步都尊重浏览器怎么读HTML。</table> -











