用途
该技能用于优化 Astro 站点的 Core Web Vitals 与加载性能,目标是让每个页面通过 Core Web Vitals 并在移动端 Lighthouse 取得 90+ 分数,从而影响 SEO 排名、抓取优先级与转化率。
性能指标目标
Core Web Vitals 的目标区间如下:
- LCP(最大内容绘制):良好 ≤2.5s,需改进 2.5–4s,差 >4s
- INP(交互到下次绘制):良好 ≤200ms,需改进 200–500ms,差 >500ms
- CLS(累积布局偏移):良好 ≤0.1,需改进 0.1–0.25,差 >0.25
关键路径规则
关键渲染路径最多 3 跳:HTML → CSS → LCP 图片。任何增加第 4 跳的因素(字体进入 CSS 链、多余 CSS 文件、未预加载的图片)都会在移动端给 LCP 增加 150–500ms,这是移动端低分的主要原因。
主要能力
-
LCP 预加载:每个页面必须把自身英雄图传给 BaseLayout 的 preloadImage 属性以进行预加载。BaseLayout 会渲染
<link rel="preload" as="image" ... fetchpriority="high">;preloadImage 会依据扩展名自动识别 MIME 类型;每个页面传自己的英雄图,不得所有页面硬编码同一张图;每页只允许一个 fetchpriority="high"(即预加载与 img 标签处)。 -
字体策略:主字体(正文、标题)使用 font-display: swap 并在 head 中预加载;非关键变体(斜体、展示体、装饰体)使用 font-display: optional 加懒加载 CSS。原因在于主 CSS 中的字体会被加入关键路径链(HTML → CSS → 字体,增加 300–500ms),将非关键字体移到懒加载 CSS 可将其从链中移除。不得预加载非关键字体,否则会抵消懒加载效果。
-
图片:使用 astro-images 技能的 Picture 组件与基于模式的 srcset。关键规则包括:始终三种格式 AVIF → WebP → JPG(照片不使用 PNG 回退);每个模式包含 480w 变体;仅在英雄图与首屏使用 loading="eager";非首屏一律 loading="lazy";英雄图绝不用 lazy,非首屏绝不用 eager;所有图片包括 SVG 都要有显式 width/height;宽高须匹配交付尺寸而非原始源尺寸。
-
第三方脚本:对首屏渲染非必需的一切脚本都延迟加载。GTM ID 来自 siteConfig.tracking.gtmId,仅 deferGtmMs 为属性;FB Pixel 若直接加载须用 setTimeout;Tag Gateway 在 Cloudflare 仪表板中管理,不在代码中。
-
CSS 策略:只保留一个主 CSS 文件(Layout.css)作为唯一允许的阻塞渲染 CSS;仅用于非首屏的组件 CSS 使用
<style is:inline>移入 HTML body,而非 head 中的阻塞 link;除非首屏绝对需要,否则不在 head 添加额外样式表 link;非首屏组件 CSS 内联总量需监控,不应超过 2KB。 -
CLS 预防:每个 img 与 iframe 都需要 width 与 height 属性,包括 SVG 图片(从 SVG viewBox 读取尺寸);使用 aspect-ratio CSS 作为后备;用 min-height 为动态内容预留空间。
-
体积预算:自有 JS <50KB gzipped;含第三方的总 JS <100KB gzipped;总 CSS <50KB gzipped;英雄图 <200KB;单张图片 <100KB;OG 图片每张 <150KB(JPG q80)。
-
缓存:带哈希的资源(/_astro/*)使用 Cache-Control: public, max-age=31536000, immutable;HTML 使用 public, max-age=0, must-revalidate;字体使用 public, max-age=31536000, immutable。
使用方式
在项目中首次使用时,复制 BaseLayout 样板:cp assets/boilerplate/layouts/BaseLayout.astro → src/layouts/BaseLayout.astro;若项目已有则跳过。该 BaseLayout 负责 LCP 预加载、GTM 延迟、Schema.org 渲染与 meta 标签。页面通过向 BaseLayout 传入 preloadImage 与 title 生效,例如传入 preloadImage="/img/hero-480w.avif"。第三方脚本延迟可通过 BaseLayout 的 deferGtmMs 属性配置。
测试与验证
Lighthouse 移动端分数在多次运行间会波动 ±10–15 分,属正常现象;慢速 4G 模拟是非确定性的,同一页面可能一次 65 分、下一次 92 分。建议运行 3–5 次取中位数;本地使用 lighthouse --preset=perf 获得更一致结果;Google 排名使用真实用户数据(CrUX)而非单次 Lighthouse 运行;90+ 之后不必追逐个位数提升。资料提供了本地批量测试的命令示例,用于循环运行 Lighthouse 并输出各次分数。
子页面性能检查清单要求不只测试首页,至少测试:首页、最长的服务页(内容最多)、地区/位置页、评论页(DOM 元素多)、计算器页(JS 密集)。常见的子页面问题包括:head 中过大的内联 JSON-LD schema(应移到 body 末尾或精简)、一次性渲染大量评论卡片(DOM 过大、布局变慢)、缺少 preloadImage 属性(英雄图发现过晚)、组件产生额外 <style is:inline> 块(HTML 体积膨胀)。
与其他技能的衔接
- astro-images:使用 Picture 组件与模式,LCP 图片对应 lcp 属性
- design-tokens:颜色对比度(WCAG AA 4.5:1),对比度不足属于无障碍问题而非性能问题,但 Lighthouse 会一并报告
- schema-entity-graph:站点地图 lastmod 需与 schema 中 dateModified 同步,虽非性能问题但常在同一次修复中处理
- deployment:部署前检查、Cloudflare Workers 配置、构建时图片处理使用 output: 'static'
禁止事项
资料明确列出多项禁止做法,包括:在 body 中添加额外样式表 link(非首屏组件 CSS 应改用 <style is:inline>);为下方组件在 head 添加额外样式表 link;head 中同步第三方脚本;照片图片使用 PNG 回退(应使用 JPG);未优化或缺少 AVIF+WebP 变体的图片;非关键字体变体使用 font-display: swap(应使用 optional 加懒加载 CSS);非关键字体变体放在阻塞渲染 CSS 中;使用 font-display: block(最多阻塞渲染 3s);预加载非关键字体;英雄图使用 loading="lazy";下方图片使用 loading="eager";任何 img 或 iframe(含 SVG)缺少 width/height;宽高设为原始源尺寸而非交付尺寸;动态内容无预留空间导致布局偏移;主线程阻塞超过 50ms 未分块;每页超过一个 fetchpriority="high";在 Layout 中硬编码预加载 URL(应按页使用 preloadImage 属性);在 HTML 中修改 Cloudflare Tag Gateway 脚本(/ry2s/)。
完成标准
资料给出的完成标准包括:首页移动端 Lighthouse ≥90(3 次运行中位数);最差子页 ≥85(3 次中位数);LCP 首页 ≤2.5s、子页 ≤3.5s;所有页面 CLS ≤0.1;计算器/交互页 INP ≤200ms;关键路径最多 3 跳;关键路径链中无字体;自有 JS <50KB gzipped;每页 preloadImage 属性指向正确的英雄图;英雄图已预加载、loading="eager"、fetchpriority="high";所有下方图片 loading="lazy";所有 img 与 iframe 含宽高(包括 SVG);字体自托管并采用正确 display 策略;第三方脚本延迟(GTM 使用 deferGtmMs,FB 使用 setTimeout);OG 图片由英雄图生成(5 个变体,JPG);至少测试 3 种不同页面类型,而不仅是首页。