关键CSS内联必须紧贴<meta charset="utf-8">之后作为<head>中第二个标签,禁用@import,体积控制在1KB–14KB间,需基于真实视口动态提取首屏样式并验证;非首屏HTML应延迟注入而非display: none。
浏览器按顺序解析HTML,<style>标签的位置直接决定它能否抢在阻塞资源前生效。如果它被放在任何<link rel="stylesheet">之后,哪怕只隔一个<title>,浏览器就会先暂停渲染去加载那个外部CSS。
常见错误现象:FCP没改善、甚至变差,DevTools里看到Parse HTML阶段卡在某个main.css请求上——说明关键CSS没抢到“首发位”。
<meta charset="utf-8">必须是<head>第一个标签<style>必须是第二个,且不能有空行、注释或其它标签插在中间<link rel="stylesheet">必须严格排在这之后@import,它会在<style>内部触发同步网络请求,等价于新增阻塞点很多人以为“越多越快”,但实测表明:内联CSS从1KB涨到5KB,在3G弱网下会使HTML主文档传输延迟增加400ms以上,TTFB和初始解析都受影响。服务端也无法缓存这部分样式,每次HTML变更都得重传全部内联内容。
真正有效的提取,必须基于真实视口和首屏DOM节点动态捕获,不是截取main.css开头部分。
立即学习“前端免费学习笔记(深入)”;
critters(Vite/webpack)或critical CLI驱动Puppeteer,模拟{ width: 375, height: 667 }访问页面jsx-abc123)识别率低,建议SSR时用renderStylesToString()序列化关键样式14KB以内(HTTP/2帧大小限制),gzip后目标为4–8KB
display: none包裹非首屏区块仍会参与CSSOM计算和DOM构建,只是不绘制;真正要的是“不创建”。
所谓“非首屏”,是指用户滚动前不可见、且不参与初始布局计算的内容。强行渲染它们会延长DOM构建时间、增加内存占用,并可能触发无谓的重排。
<template>或纯JS动态插入(innerHTML或document.createElement)data-html属性暂存字符串,切换时再解析挂载Rendering > FPS Meter和Layers面板可观察首屏区域是否包含大量隐藏/折叠节点<link rel="preload">不是越多越好,滥用会抢占带宽、挤掉真正关键的资源。它只影响下载优先级,不改变执行时机。
判断是否该preload的简单标准:这个资源是否在DOMContentLoaded前就必须就位?如果不是,大概率不需要。
<h1>背景图、关键Web字体(注意加crossorigin)<link rel="preload" as="style">不能替代内联,只能辅助非关键CSS;预加载的样式仍需后续<link>挂载,无法参与初始渲染树构建<script>都preload:它不会推迟执行,反而可能干扰真正关键的资源preload,无副作用,但别指望它解决兼容性问题最容易被忽略的一点:内联关键CSS不是“复制粘贴”,而是提取 + 验证。工具生成后必须打开DevTools → Network → Disable cache,刷新看FCP是否提前,再对比移除内联后的差异。否则优化可能只是假象。