< BACK 大型网站的核心网络生命体征:如何实现低于1.5秒的LCP -- 线条风格插图

大型网站的核心网页指标:如何达到1.5秒以下的LCP

早在 2022 年,一个主机对比网站的项目落到了我的案头。大型目录,约 4,000 个页面,类别结构深度嵌套,联盟链接散布其中,英雄图像大得离谱。他们的 Google Search Console 状况糟糕透顶。移动端 LCP 停留在 4.2 秒。INP(当时还叫 FID)勉强达标。客户已经花了 6,000 英镑给前一家代理商,他们只是部署了一个 CDN 然后拍拍屁股走人。

那个项目最终塑造了我们在 Seahawk 对高页面数网站、目录网站、列表平台、HostList 风格的主机评测网站等的性能理解方式。接下来是实际的执行手册。performance at Seahawk for high-page-count sites, directory sites, listing platforms, hosting review properties like HostList-style builds. What follows is the actual playbook.

---

为什么大型网站的LCP问题不同

小型网站有简单的问题。一个英雄图像、一个主题、一个插件做太多事情。修复这三样东西,你就可以在2秒以内了。

大型网站?完全是另一种动物。LCP 元素因页面而异。类别归档页的 LCP 候选元素与产品详情页不同,与首页也不同。大多数性能工具报告单一分数。这个数字是谎言,它是一大堆差异巨大的页面的平均值,只修复首页而忽视底下 3,800 个列表页正是代理商获得恶名的方式。which page you're on. A category archive has a different LCP candidate than a product detail page, which has a different candidate than the homepage. Most performance tools report a single score. That number is a lie, it's an average of a wildly varied set of pages, and fixing the homepage while ignoring the 3,800 listing pages underneath it is exactly how agencies earn bad reputations.

Google 的 Core Web Vitals 文档很明确:现场数据,即真实用户体验,在 Chrome 用户体验报告中测量,才是 Google 用于排名信号的内容。PageSpeed Insights 的实验室数据只是参考,不是决定性的。我见过网站在 PSI 上得分 95,但 CrUX 数据中 LCP 仍是差评。别搞混了。Core Web Vitals documentation from Google is clear that field data, what real users experience, measured in Chrome User Experience Report, is what Google actually uses for ranking signals. Lab data from PageSpeed Insights is directional, not definitive. I've seen sites score 95 on PSI and still have Poor LCP in CrSX data. Don't confuse the two.

列表网站上的三个真实罪魁祸首

在我审计过的每个大型网站上(到目前为止我已经审计了数百个),LCP 失败几乎总是归结为三个根本原因:

  • 未优化的英雄图或卡片图,通常以完整分辨率提供,格式错误,没有 fetchpriority 提示, often served at full resolution, wrong format, no fetchpriority hint
  • 渲染阻塞的第三方脚本,联盟追踪器,广告网络,对比小部件在浏览器绘制任何内容之前加载, affiliate trackers, ad networks, comparison widgets loading before the browser can paint anything
  • TTFB 膨胀了 LCP 预算,服务器响应缓慢在页面开始加载之前吃掉 600-900 毫秒, slow server response eating 600-900ms before the page even starts loading

第三个是人们低估的。如果你的 TTFB 是 700 毫秒,在浏览器渲染单个像素之前,你已经花掉了近一半的"良好"LCP 预算。主机选择和服务器端缓存不是 DevOps 的问题,是 SEO 的问题。

---

从 TTFB 开始:这首先是一个托管和缓存问题

我上面提到的HostList类型的项目?我做的第一件事是从五个不同的地理位置运行WebPageTest。TTFB一直稳定在680-820ms。网站在弗吉尼亚的共享主机上。他们的大部分有机流量来自英国和德国。WebPageTest from five different geographic locations. TTFB was consistently 680-820ms. The site was on a shared host in Virginia. Most of their organic traffic came from the UK and Germany.

把网站迁移到了一个托管WordPress主机,在伦敦和法兰克福设有边缘节点。配置了完整页面缓存,列表页面的缓存生命周期设置为12小时(数据反正也不经常变化)。在重复请求中TTFB下降到120-180ms,首次缓存未命中时为280-350ms。这一项改动就让LCP减少了约500ms,还没有优化过任何图片。WordPress host with edge nodes in London and Frankfurt. Configured full-page caching with cache lifetimes of 12 hours on listing pages (the data didn't change that often anyway). TTFB dropped to 120-180ms on repeat requests, 280-350ms on first-hit cache misses. That single change shaved roughly 500ms off LCP before I touched a single image.

关于托管方面,我总是检查以下几点:

  1. 全页缓存是否真的在工作?检查X-Cache响应头。如果每个请求都显示MISS,说明你的缓存层没有正常运作。 Check the X-Cache response header. If it says MISS on every single request, your caching layer isn't functioning.
  2. 源服务器地理位置是否靠近你的主要受众?这听起来很明显。但你会惊讶于这一点多么经常出错。 This sounds obvious. You'd be surprised how often it's wrong.
  3. 是否启用了keep-alive?一些便宜的主机仍然禁用持久连接。在2024年这样做很离奇,但确实会发生。 Some cheaper hosts still disable persistent connections. Wild in 2024, but it happens.
  4. HTTP/2或HTTP/3是否活跃?运行curl -I --http2 https://yourdomain.com并检查响应中的协议。 Run curl -I --http2 https://yourdomain.com and check the protocol in the response.

在解决TTFB之前不要动图片优化。在一个慢速服务器上优化图片就像给一栋着火的房子粉刷一样。

---

LCP图片问题(以及为什么`fetchpriority`改变了一切)

对。图像。在具有卡片网格布局的列表网站上,LCP 元素几乎总是第一张首屏上方的卡片图像,或英雄横幅。浏览器必须发现它、获取它、解码它并渲染它。这些步骤中的每一个都可能被延迟。

以下是我们在 HostList 项目中实际所做的,按顺序:

  1. 使用 Imagify 的批量转换功能,将所有卡片图像转换为 WebP 格式。在我们使用的卡片缩略图尺寸(280×180px 显示,视网膜屏幕下 2 倍像素)上,平均文件大小下降了 58%,视觉质量没有明显损失。, using Imagify's bulk conversion. Average file size dropped 58% without visible quality loss at the card thumbnail sizes we were using (280×180px display, served at 2x for retina).
  2. 在第一张卡片图像上添加了 `fetchpriority="high"`。仅此一项改动就在 WebPageTest 的测试中将 LCP 降低了约 200ms。浏览器停止将其视为普通的懒加载图像,而是立即将其加入预加载扫描器的队列。, This one change alone knocked ~200ms off measured LCP in WebPageTest. The browser stops treating it like a regular lazy image and queues it immediately in the preload scanner.
  3. 从前两行卡片图像中移除了 `loading="lazy"`。懒加载对折叠线下方的图像非常有效。但在第一个可见行上,它反而有害。它告诉浏览器在图像接近视口时再获取,而此时图像已经在视口内了。, Lazy loading is brilliant for below-fold images. On the first visible row, it actively hurts you. It tells the browser to not fetch the image until it's near the viewport, which it already is.
  4. 在首页模板的 `<head>` 中为 hero 图片添加了 `<link rel="preload">` 标签。 in the <head> on the homepage template specifically.

这个流程把首页的 LCP 从 3.1 秒降低到了 1.4 秒(在实验条件下)。现场数据在大约 28 天内跟进(这大约是 CrUX 数据在大规模反映变化所需的时间)。

关于响应式图片的说明

如果你向移动设备提供同一张 1400px 宽的图像,你就是在浪费带宽并增加解码时间。正确使用 srcset。我知道这听起来像是 2016 年的话题,但我仍然在大约 40% 经过 Seahawk 的网站上看到这种情况。WordPress 的 wp_get_attachment_image() 函数会自动生成 srcset,但前提是图像上传时分辨率足够高,且主题没有通过 add_filter('max_srcset_width', ...) 禁用它。srcset properly. I know this sounds like a 2016 conversation but I still see it on probably 40% of the sites that come through Seahawk. The WordPress wp_get_attachment_image() function generates srcset automatically, but only if the image was uploaded at sufficient resolution and the theme hasn't suppressed it with add_filter('max_srcset_width', ...).

---

阻塞渲染的脚本:联盟网站的税收

主机对比网站和列表平台靠联盟营收维生。这意味着有第三方跟踪脚本。Commission Junction、Impact、Awin、自定义像素追踪器,它们堆积起来。我在一个列表网站上数过 14 个独立的第三方脚本来源。每一个都需要单独的 DNS 查询、TCP 连接和 TLS 握手,然后才能收到该脚本的一个字节。

修复方案不是移除这些脚本。你不能这样做,收入取决于它们。修复方案是排序。

没有第三方脚本应该阻塞LCP元素的初始渲染。句号。

在实际操作中,这意味着:

  • 将所有联盟/分析脚本移到DOMContentLoaded事件之后加载,而不是在<head>中。after the DOMContentLoaded event, not in <head>.
  • 在你控制的每个脚本上使用async或defer属性。async or defer attributes on every script you control.
  • 对于你无法控制的脚本(由标签管理器注入),使用 defer 加载 Google Tag Manager 本身。是的,这对大多数联盟跟踪用例是安全的,GTM 自己的文档也承认这种方法。defer, yes, this is safe for most affiliate tracking use cases, and GTM's own documentation acknowledges this approach.
  • 使用Asset CleanUp Pro或WP Rocket的脚本延迟功能等脚本管理器,将非必要的第三方脚本延迟加载到用户交互(首次滚动或首次点击)时。

在HostList.io重建中,延迟第三方脚本将总阻塞时间从1,840ms减少到290ms。TBT本身不是Core Web Vital,但它与INP的相关性很强,而INP是。is.

---

字体加载:那个无人谈论的 LCP 隐形杀手

自定义字体会引发特定的故障模式。浏览器渲染你的布局,到达 LCP 文本元素(有时 LCP 是标题而非图像),然后在绘制前等待字体文件。这称为不可见文本闪烁,它会根据字体文件大小和服务器距离延迟 LCP 200ms 到超过一秒。

两件事可以解决这个问题:

  • 在你的 @font-face 声明中加入 `font-display: swap`,浏览器会立即用备用字体渲染,当自定义字体加载完成时再替换。LCP 候选项按时被绘制。 in your @font-face declaration, the browser renders in a fallback font immediately and swaps when the custom font loads. LCP candidate gets painted on time.
  • 自托管你的字体。Google Fonts 会增加跨域请求。使用 google-webfonts-helper 工具自托管,你可以从自己的域名提供字体,节省额外的连接。google-webfonts-helper tool lets you serve fonts from your own domain, cutting that extra connection.

我用那个工具在大约 45 分钟内把一个大型目录网站从 Google Fonts 迁移出来。LCP 改进了 180ms。单独看不是革命性的,但结合其他所有优化,这些边际收益会复合增长。

---

衡量实地中真正重要的指标

CrUX 数据是基础事实。但它只按月更新,且仅适用于流量足够的 URL。对于拥有数千个页面的大型网站,你需要更细粒度的数据。

我在代表性的 URL 样本上使用 PageSpeed Insights API 脚本化测试,通常包括按流量排名前 100 的页面、50 个分类级页面和 20 个"瘦"深目录页面。每月运行一次可以得到适当的性能分布,而不是单点分数。PageSpeed Insights API scripted across a representative sample of URLs, typically the top 100 pages by traffic, 50 category-level pages, and 20 "thin" deep-catalogue pages. Running this monthly gives a proper performance distribution, not a single-point score.

在 Lighthouse CI 中(我们在为具有开发周期的客户的 CI/CD 管道中运行),我们对以下指标进行断言:

  • LCP ≤ 2.5s(实验室环境,保守目标,因为实际环境通常比实验室环境慢 10-15%)
  • TBT ≤ 300ms
  • CLS ≤ 0.1

但老实说,对于目标是 LCP 低于 1.5 秒的 HostList 类型构建,实验室目标需要更严格。我们在这些项目的 Lighthouse CI 中设置 LCP ≤ 1.8s,一旦 CrUX 赶上进度,通常会在实测数据中产生 1.3-1.5s 的结果。

---

汇总:HostList 的结果

在运行完上述所有操作后——托管迁移、全页面缓存、图像格式转换、LCP 候选项的 fetchpriority、移除首屏行的延迟加载、脚本延迟执行和字体自托管——数据看起来是这样的:fetchpriority on LCP candidates, lazy-load removal from above-fold rows, script deferral, and font self-hosting, here's what the numbers looked like:

  • TTFB: 780ms → 160ms(中位数,英国访客): 780ms → 160ms (median, UK visitors)
  • LCP(实验室,移动端):4.2s → 1.4s: 4.2s → 1.4s
  • LCP(实际,CrUX,75 百分位):3.8s → 1.6s(迁移后 60 天测量): 3.8s → 1.6s (measured 60 days post-migration)
  • TBT:1,840ms → 290ms: 1,840ms → 290ms
  • CLS:原本就不错,为 0.03,未改变: was already fine at 0.03, unchanged

并非每个网站都能获得 2.8 秒的提升。但我做过的几乎所有大型列表网站都同时存在这些问题,这意味着收益是叠加的。修复一个问题你能获得 300ms 的提升。全部修复你就能获得 2.5 秒。

---

常见问题

托管服务对 LCP 的影响真的那么大吗?

是的,可能比其他任何东西在开始时都重要。如果你的 TTFB 高于 500ms,再多的图像优化也无法让你达到"优秀"LCP。TTFB 是其他一切的基础。先把它降到 200ms 以下,然后再考虑其他的。

我应该使用 CDN 而不是迁移主机吗?

CDN 有助于静态资源交付,如果配置得当,可以降低缓存整页 HTML 的 TTFB。但许多 CDN 设置只缓存资源,不缓存整个 HTML 响应。检查你的 CDN 是否真的在提供缓存的 HTML,还是只在卸载图像。如果是后者,更好的源主机对 LCP 的改进会更大。

`fetchpriority="high"` 现在得到广泛支持了吗?

截至 2024 年,是的,它在 Chrome、Edge 和 Safari(自 Safari 17.2 起)中得到支持。Firefox 支持在 Firefox 132 中推出。对于不支持它的浏览器,它被安全地忽略。将它添加到你的 LCP 图像元素上没有任何缺点。

CrUX 数据需要多长时间才能反映改进?

从真实用户开始体验网站更快版本起,大约需要 28 天。CrUX 使用滚动 28 天窗口。所以如果你今天部署更改,你的字段数据分数在大约一个月后才会完全反映这些改变。如果在优化冲刺的第二天 PageSpeed Insights 仍然显示"需要改进",不用惊慌。

对于列表网站,单一最高影响力的改变是什么?

在几乎每个项目上,都是 TTFB。但第二高的一致是从首屏卡片图像中移除 loading="lazy" 并添加 fetchpriority="high"。这两个操作通常占总 LCP 改进的 40-60%。其他一切都是在这个基础之上的复合收益。loading="lazy" from above-fold card images and adding fetchpriority="high". Together those two things usually account for 40-60% of the total LCP improvement. Everything else is compounding gains on top of that foundation.

---

大型网站的性能工作主要是基础设施工程。乏味、有条不紊,但当你把 4 秒的 LCP 降低到 1.4 秒,两个月后看到有机流量提升时,会深感满足。没有什么灵丹妙药,只是按正确顺序做出的一系列具体决策。

让服务器变快。然后让 LCP 元素被及早发现和获取。然后让其他一切都为它让路。

< BACK