HTML本身极少是瓶颈,白屏主因是同步script、未处理字体、错误preload或file://协议导致优化失效;需用Network面板定位阻塞资源,内联首屏关键CSS(≤10KB原始体积),defer脚本并动态加载第三方资源。

HTML 本身 rarely 是瓶颈——index.html 文件通常不到 50KB,解析开销极小。真正拖慢“用户看到内容”的,是它一加载完立刻触发的阻塞行为:同步 script、未处理的 @font-face、错误的 preload、或本地 file:// 协议下所有优化全部失效。
为什么 Network 面板显示 index.html “完成”了,页面还是白屏?
这是最常被误解的点:HTML 下载完成 ≠ 页面可渲染。浏览器必须等以下任一条件满足才肯画第一帧:
-
link[rel="stylesheet"]下载并解析完成(哪怕它在<head>最末尾) - 没有
defer或async的<script>执行完毕(包括内部document.write()或同步fetch) - 关键字体(
font-display: block且未缓存)加载失败或超时
实操建议:在 Chrome DevTools 的 Network 面板中过滤 Doc 类型,确认 index.html 的 TTFB 和下载时间;再切到 All,按 Waterfall 排序,重点看排在前 3 位的 main.css、vendor.js、fonts.gstatic.com 是否耗时 >800ms。
关键 CSS 必须内联,但别超 10KB 原始体积
内联不是“把所有 CSS 塞进 <style>”,而是只放首屏必需的规则:比如 body、.hero、.nav 的布局、颜色、字体声明。其他样式一律外链。
立即学习“前端免费学习笔记(深入)”;
- 用 Chrome DevTools 的
Coverage面板(More Tools → Coverage)刷新页面,红色部分就是未使用的 CSS 字节,直接删 - 内联
<style>中禁止出现@import——它会发起新请求,彻底破坏内联意义 - gzip 后体积建议 ≤ 4–8KB(对应原始体积约 10–14KB),否则可能跨 TCP 包,反而拖慢 TTFB
- 内联后,记得移除对应外链的
<link rel="stylesheet">,否则样式重复应用,可能引发意外交互
script 标签加 defer 不等于万事大吉
defer 只解决 HTML 解析阻塞,不解决执行时机和主线程抢占问题。
- 如果
main.js里有大量计算或 DOM 操作,首屏交互仍会卡顿 - 第三方脚本(如统计、客服)必须用
async,且最好动态注入:fetch()+eval()或createScript,避免初始 HTML 里硬编码<script src="analytics.js"> - 非首屏 JS(如轮播图、表单校验)应延迟到
requestIdleCallback(() => { /* load */ })或至少DOMContentLoaded后再初始化 - 绝对禁用
document.write():现代浏览器已废弃,执行即清空文档流,本地环境尤其敏感
loading="lazy" 加错图片反而害性能
原生懒加载只对 <img> 和 <iframe> 生效,且有明确限制。
- 所有加
loading="lazy"的<img>必须显式设置width和height属性,否则滚动时加载会引发布局偏移(CLS) - 首屏图片必须去掉
loading="lazy",确保立即加载;非首屏才加 - Safari 15.4+ 才支持
loading="lazy"对<iframe>的支持;旧版安卓 WebView 可能完全忽略,需降级为data-src+IntersectionObserver - 别同时写
src和loading="lazy"再额外用 JS 监听——浏览器可能先加载src,造成重复请求
最易被忽略的一点:直接双击打开 HTML 文件走的是 file:// 协议,此时 gzip/Brotli、HTTP/2、DNS 预解析、跨域缓存全失效,路径错一个、404 一次、base64 图片塞一串,就立刻暴露。临时起个本地服务器(如 python3 -m http.server)再测,能快速排除干扰。



















