<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged lcp</title>
<link>https://coderlegion.com/tag/lcp</link>
<description>Powered by Question2Answer</description>
<item>
<title>Critical CSS and Render-Blocking Resources: Faster First Paint Without Guessing</title>
<link>https://coderlegion.com/32782/critical-css-and-render-blocking-resources-faster-first-paint-without-guessing</link>
<description>&lt;p&gt;Lighthouse keeps recommending “Eliminate render-blocking resources,” and the usual response is to inline more CSS or defer everything in sight. That can help First Contentful Paint. It can also ship a Flash of Unstyled Content, bloat the HTML response, or leave Largest Contentful Paint worse than before.&lt;/p&gt;
&lt;p&gt;Critical CSS is a narrower job: ship only the styles needed for the first viewport as soon as HTML arrives, then load the remainder without blocking that first paint. The method is measurable. Chrome’s Coverage tab shows what was used on load; guessing from a theme “optimise” toggle is not the same work.&lt;/p&gt;
&lt;p&gt;The sections below walk through extraction and deferral for agency sites. For what First Contentful Paint and Total Blocking Time mean in lab reports, keep &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/fcp-tbt-supporting-metrics-beyond-core-web-vitals&quot;&gt;FCP and TBT: Supporting Metrics Beyond Core Web Vitals&lt;/a&gt; open. For Largest Contentful Paint thresholds and fixes, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, CLS: What Each Core Web Vital Means and How to Fix It&lt;/a&gt;. Resource hints that pair with deferred CSS are covered in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/preload-prefetch-preconnect-resource-hints-faster-core-web-vitals&quot;&gt;Preload, Prefetch, and Preconnect: Resource Hints for Faster Core Web Vitals&lt;/a&gt;. The full browser critical rendering path (DOM, CSSOM, layout, paint) is a separate map; here the focus stays on CSS extraction and render-blocking stylesheets.&lt;/p&gt;
&lt;h3 id=&quot;what-critical-css-is-and-what-it-is-not-&quot;&gt;What critical CSS is (and what it is not)&lt;/h3&gt;
&lt;p&gt;Critical CSS is the subset of rules required to render content that is visible in the initial viewport (sometimes called above the fold). Google’s performance guides describe it as styles needed so the browser can paint meaningful content without waiting for every stylesheet on the network. That definition is deliberately smaller than “the CSS file the theme already ships.”&lt;/p&gt;
&lt;p&gt;It is not “all CSS for the homepage,” and it is not a substitute for removing unused CSS from the full bundle. It is also not the same as understanding every stage of the critical rendering path. Critical CSS answers a shipping question: which rules must travel with the first HTML response so first paint is not stuck behind a large &lt;code&gt;link rel=&quot;stylesheet&quot;&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;When the critical set is too large, you pay HTML bytes on every document request, often with a short cache lifetime. When it is too small, users see unstyled or partially styled content until the deferred sheet arrives. The useful size is usually the Coverage-green set for the templates you care about on mobile, plus a margin for the Largest Contentful Paint element’s layout.&lt;/p&gt;
&lt;h3 id=&quot;how-render-blocking-css-delays-first-contentful-paint-and-largest-contentful-paint&quot;&gt;How render-blocking CSS delays First Contentful Paint and Largest Contentful Paint&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.apogeewatcher.com/blog-images/98-render-blocking-css-delays-fcp-lcp.webp&quot; alt=&quot;Schematic comparing default render-blocking CSS with critical CSS inlined: left panel shows site.css blocking CSSOM then late FCP and LCP; right panel shows critical styles in the HTML response, deferred full CSS, and earlier FCP and LCP&quot;&gt;&lt;/p&gt;
&lt;p&gt;By default, CSS is render-blocking. The browser builds the CSS Object Model before it paints, so it avoids a Flash of Unstyled Content. That behaviour is intentional. The cost appears when a large shared stylesheet must finish downloading and parsing before any text or hero layout appears.&lt;/p&gt;
&lt;p&gt;In Lighthouse and PageSpeed Insights, that cost shows up as the Eliminate render-blocking resources opportunity: stylesheet (and script) URLs that sit on the critical path to first paint. First Contentful Paint moves when those bytes clear earlier. Largest Contentful Paint can improve when the LCP element’s styles and related layout rules are available sooner, but LCP still depends on the LCP resource itself (image, text block, or video poster). Fixing render-blocking CSS does not replace image optimisation for a heavy hero.&lt;/p&gt;
&lt;p&gt;Scripts marked without &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt; can block parsing as well. Stylesheets are the subject here. Script deferral and Interaction to Next Paint belong on a separate main-thread checklist; not every render-blocking URL in the audit is a CSS problem.&lt;/p&gt;
&lt;h3 id=&quot;how-to-find-critical-css-with-chrome-devtools-coverage&quot;&gt;How to find critical CSS with Chrome DevTools Coverage&lt;/h3&gt;
&lt;p&gt;Extraction works best from evidence, not from a plugin default. Theme toggles that claim to eliminate render-blocking resources rarely show which rules still matter for first paint. A practical Coverage pass looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the page on a representative mobile viewport (or device mode that matches your lab strategy).&lt;/li&gt;
&lt;li&gt;Open DevTools → Command Menu → &lt;strong&gt;Show Coverage&lt;/strong&gt;, then reload so the report captures the initial load.&lt;/li&gt;
&lt;li&gt;Inspect each stylesheet URL. Green marks rules used for that load; red marks unused rules in that file for that load.&lt;/li&gt;
&lt;li&gt;Treat green rules that style above-the-fold content (header, hero, primary text, navigation chrome) as candidates for the critical set. Red rules for below-the-fold accordion bodies, footers, and dormant components usually belong in the deferred sheet.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Coverage is a laboratory sample. A cookie banner that appears after consent, or a mega-menu that opens on hover, may need styles that were red on a cold load. Those rules still belong in the critical set when they affect first paint or first interaction on real client templates. For portfolio work, Coverage on home and on the conversion URL, then a careful merge of the two sets, beats inlining two full themes.&lt;/p&gt;
&lt;p&gt;Automated extractors (for example the Critical tooling family referenced in Chrome’s render-blocking docs) can speed the cut when the architecture allows it. The output still needs a Coverage check and a visual pass. Automated critical CSS that omits font-face or hero layout rules is a common FOUC source, and that failure usually shows up on mobile first.&lt;/p&gt;
&lt;h3 id=&quot;how-to-inline-critical-css-and-defer-the-rest&quot;&gt;How to inline critical CSS and defer the rest&lt;/h3&gt;
&lt;p&gt;A common pattern, documented on web.dev, looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Place the critical rules in a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; block in the document &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; (minified).&lt;/li&gt;
&lt;li&gt;Load the full stylesheet asynchronously so it does not block first paint, for example with &lt;code&gt;rel=&quot;preload&quot;&lt;/code&gt; as &lt;code&gt;style&lt;/code&gt; and an &lt;code&gt;onload&lt;/code&gt; handler that switches it to a stylesheet, plus a &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; fallback for browsers without script.&lt;/li&gt;
&lt;li&gt;Keep the inlined block small enough that the HTML response stays lean.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;head&amp;gt;
  &amp;lt;style&amp;gt;/* minified critical rules only */&amp;lt;/style&amp;gt;
  &amp;lt;link
    rel=&quot;preload&quot;
    href=&quot;/css/site.css&quot;
    as=&quot;style&quot;
    onload=&quot;this.onload=null;this.rel='stylesheet'&quot;
  /&amp;gt;
  &amp;lt;noscript&amp;gt;&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;/css/site.css&quot; /&amp;gt;&amp;lt;/noscript&amp;gt;
&amp;lt;/head&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Production sites often wrap the preload pattern in a small helper (loadCSS-style) so Content Security Policy and older browsers behave predictably. The principle stays the same either way: critical styles travel with HTML, and the bulk of the CSS arrives without blocking the first paint. The helper exists for edge cases; the measurement still comes from Coverage and a dated lab run.&lt;/p&gt;
&lt;p&gt;Deferred CSS pairs well with honest resource hints when the full sheet is still important soon after paint. A &lt;code&gt;preload&lt;/code&gt; for the stylesheet is part of that story; preloading every font and hero image at once usually blows the budget. The decision table in the resource-hints guide keeps those choices from competing with each other.&lt;/p&gt;
&lt;h3 id=&quot;media-query-stylesheets-as-a-lighter-alternative&quot;&gt;Media-query stylesheets as a lighter alternative&lt;/h3&gt;
&lt;p&gt;Not every render-blocking sheet needs full critical-CSS extraction. Styles that only apply to print, or only above a large breakpoint, can stay in separate files with a &lt;code&gt;media&lt;/code&gt; attribute. The browser still downloads them according to its rules, but it does not block first paint on media that do not match.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;/css/site.css&quot; /&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;/css/print.css&quot; media=&quot;print&quot; /&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;/css/wide.css&quot; media=&quot;(min-width: 64em)&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach helps when print or desktop-only rules inflate a shared bundle. It does not replace critical CSS when the default (always-matching) sheet is still huge. Media splits suit conditional CSS; extraction suits the case where the main &lt;code&gt;all&lt;/code&gt; stylesheet is the blocker Lighthouse names.&lt;/p&gt;
&lt;h3 id=&quot;mistakes-that-make-critical-css-slower&quot;&gt;Mistakes that make “critical CSS” slower&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Inlining the entire theme.&lt;/strong&gt; Critical CSS that is “most of &lt;code&gt;app.css&lt;/code&gt;” increases HTML weight on every navigation and often cannot be cached as aggressively as a hashed stylesheet. First paint may still improve on a cold cache, but TTFB and transfer size can suffer on repeat views and multi-page sessions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guessing without Coverage.&lt;/strong&gt; Theme or page-builder toggles that claim to eliminate render-blocking resources often defer styles the first paint still needs. The result is FOUC, layout thrash, or a late Cumulative Layout Shift when the full sheet arrives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Forgetting the Largest Contentful Paint element.&lt;/strong&gt; If the LCP node is a text block or image whose dimensions depend on deferred rules, a generic render-blocking audit can go green while LCP stays red. LCP styles belong in the critical set, and the LCP resource itself still needs its own optimisation. Agency reports that celebrate a cleared opportunity while LCP stays amber lose credibility fast.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Skipping &lt;code&gt;noscript&lt;/code&gt; or CSP-safe loading.&lt;/strong&gt; Async CSS patterns that rely only on inline &lt;code&gt;onload&lt;/code&gt; handlers can fail under strict Content Security Policy. A fallback matters when the client’s security headers are strict. Test the pattern under the same CSP the production site already ships.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Treating one homepage pass as the portfolio.&lt;/strong&gt; Agency sites share templates. Critical CSS extracted only from a brochure home can miss booking or checkout chrome. Coverage on the conversion URL before you declare the set done catches that gap.&lt;/p&gt;
&lt;h3 id=&quot;how-to-verify-the-change-in-lighthouse-and-monitoring&quot;&gt;How to verify the change in Lighthouse and monitoring&lt;/h3&gt;
&lt;p&gt;After critical CSS ships, a useful verification loop looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Record the laboratory tool, URL, strategy (mobile or desktop), and date for a before baseline.&lt;/li&gt;
&lt;li&gt;Re-run Lighthouse or PageSpeed Insights on the same URL and strategy. Check Eliminate render-blocking resources, First Contentful Paint, and Largest Contentful Paint together.&lt;/li&gt;
&lt;li&gt;Visually confirm first paint on a throttled mobile profile: no long unstyled flash, hero and header readable early.&lt;/li&gt;
&lt;li&gt;Watch Cumulative Layout Shift if late styles change dimensions after paint.&lt;/li&gt;
&lt;li&gt;Put a follow-up lab run on the calendar, and on other templates that share the CSS pipeline.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A single green opportunity row is not a portfolio proof. Scheduled lab tests catch the next theme update that reintroduces a blocking sheet. Budgets on FCP or LCP make that regression visible without waiting for a client complaint.&lt;/p&gt;
&lt;h3 id=&quot;faq&quot;&gt;FAQ&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Is critical CSS the same as eliminating unused CSS?&lt;/strong&gt;&lt;br&gt;
No. Unused CSS removal shrinks the full stylesheet. Critical CSS chooses which rules travel with the first HTML response. Teams usually need both over a quarter: unused CSS for transfer size, critical CSS for first paint timing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Will critical CSS always improve Largest Contentful Paint?&lt;/strong&gt;&lt;br&gt;
Not always. It helps when LCP is waiting on stylesheet work. If LCP is a large image or a slow server, those paths still need work. Reading FCP and LCP together after the change shows which lever moved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can we defer all CSS to the bottom of the body?&lt;/strong&gt;&lt;br&gt;
Moving the &lt;code&gt;link&lt;/code&gt; lower can change priority, but the browser may still treat the stylesheet as high priority and you risk FOUC. An explicit critical set plus async load of the remainder, with a &lt;code&gt;noscript&lt;/code&gt; fallback, is the more reliable pattern. Position alone rarely matches what Coverage would have selected for above-the-fold paint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do WordPress or Shopify “defer CSS” plugins replace Coverage?&lt;/strong&gt;&lt;br&gt;
They can automate a pattern, but they still need verification. Coverage plus a dated lab test on home and the conversion URL after enabling a plugin, with a rollback ready if FOUC appears, is the safer agency habit. Plugin defaults rarely know your booking or checkout chrome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How does this relate to the critical rendering path?&lt;/strong&gt;&lt;br&gt;
Render-blocking CSS is one stage of the path from HTML to pixels. Extraction and deferral are the shipping half of that story. A deeper pass on DOM, CSSOM, layout, and paint belongs in a critical rendering path guide; &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/critical-rendering-path&quot;&gt;web.dev’s Critical Rendering Path&lt;/a&gt; is the map when you need those stages named in order.&lt;/p&gt;
&lt;h3 id=&quot;measure-first-then-inline&quot;&gt;Measure first, then inline&lt;/h3&gt;
&lt;p&gt;Critical CSS works when the critical set is measured, small, and verified. Coverage decides what is above the fold; the inline block carries that set; an async pattern loads the rest. First Contentful Paint and Largest Contentful Paint on the same client URLs show whether the change stuck, and a follow-up lab run after the next theme update shows whether it stayed stuck.&lt;/p&gt;
&lt;p&gt;If those lab checks need to run on a schedule across many domains, &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/sign-up&quot;&gt;try Apogee Watcher&lt;/a&gt; or run a &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/check&quot;&gt;free domain check&lt;/a&gt; before and after the CSS change.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources&quot;&gt;Eliminate render-blocking resources&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/extract-critical-css&quot;&gt;Extract critical CSS&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/defer-non-critical-css&quot;&gt;Defer non-critical CSS&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/critical-rendering-path/render-blocking-css&quot;&gt;Render-blocking CSS&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/critical-rendering-path&quot;&gt;Critical Rendering Path&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/learn/performance/optimize-resource-loading&quot;&gt;Optimize resource loading&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/fcp-tbt-supporting-metrics-beyond-core-web-vitals&quot;&gt;FCP and TBT: Supporting Metrics Beyond Core Web Vitals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, CLS: What Each Core Web Vital Means and How to Fix It&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/preload-prefetch-preconnect-resource-hints-faster-core-web-vitals&quot;&gt;Preload, Prefetch, and Preconnect: Resource Hints for Faster Core Web Vitals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/critical-css-render-blocking-resources-faster-first-paint&quot;&gt;Apogee Watcher&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32782/critical-css-and-render-blocking-resources-faster-first-paint-without-guessing</guid>
<pubDate>Wed, 28 Oct 2026 07:59:06 +0000</pubDate>
</item>
<item>
<title>Preload, Prefetch, and Preconnect: Resource Hints for Faster Core Web Vitals</title>
<link>https://coderlegion.com/31585/preload-prefetch-and-preconnect-resource-hints-for-faster-core-web-vitals</link>
<description>&lt;p&gt;Resource hints are declarations in HTML or HTTP headers that ask the browser to prepare work before it would otherwise discover it. Four names show up in almost every PageSpeed Insights audit and WordPress “optimisation” plugin: &lt;code&gt;dns-prefetch&lt;/code&gt;, &lt;code&gt;preconnect&lt;/code&gt;, &lt;code&gt;preload&lt;/code&gt;, and &lt;code&gt;prefetch&lt;/code&gt;. They are not interchangeable, and they are not a substitute for making the Largest Contentful Paint (LCP) resource discoverable in the initial HTML.&lt;/p&gt;
&lt;p&gt;What follows is a decision guide for agencies and product teams: which hint to use, how to preload an LCP image when the browser cannot discover it early, when preconnect helps cross-origin performance, how prefetch differs from preload, and where font preloads stop helping. For metric thresholds, keep &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/what-are-core-web-vitals-a-practical-guide-for-2026&quot;&gt;What Are Core Web Vitals? A Practical Guide for 2026&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, CLS: What Each Core Web Vital Means and How to Fix It&lt;/a&gt; open. Image sizing and lazy-loading rules belong with preload work, so use &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores&quot;&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lazy-loading-lcp-cls-loading-lazy-attribute&quot;&gt;Lazy Loading for LCP and CLS: When to Use&lt;/a&gt; &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lazy-loading-lcp-cls-loading-lazy-attribute&quot;&gt;(and When Not To)&lt;/a&gt; beside this guide.&lt;/p&gt;
&lt;h3 id=&quot;what-resource-hints-change-for-core-web-vitals-and-what-they-do-not-&quot;&gt;What resource hints change for Core Web Vitals (and what they do not)&lt;/h3&gt;
&lt;p&gt;Hints change &lt;em&gt;when&lt;/em&gt; the browser starts DNS, TCP/TLS, or a fetch. They do not compress files, resize a hero image, or fix a render-blocking stylesheet on their own. Google’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/learn/performance/resource-hints&quot;&gt;resource hints course&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/preload-critical-assets&quot;&gt;preload critical assets&lt;/a&gt; guidance treat them as assists for late-discovered critical work, not as a general “speed up everything” layer.&lt;/p&gt;
&lt;p&gt;LCP benefits most when the LCP image or font is discoverable early, or when a carefully scoped &lt;code&gt;preload&lt;/code&gt; with &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt; covers a late-discovered candidate. Interaction to Next Paint (INP) and Cumulative Layout Shift (CLS) usually move for other reasons (busy main thread, missing reserved space). Adding twenty &lt;code&gt;preconnect&lt;/code&gt; tags will not repair a 4 MB hero or a lazy-loaded above-the-fold banner.&lt;/p&gt;
&lt;p&gt;For agencies, the reporting risk is the same as with other lab tips: a plugin adds hints sitewide, Lighthouse’s unused-preload warnings appear, and the client report claims “we implemented preconnect” without naming origins or measuring before and after. Label the hint, the origin or URL, and the dated lab row. Without those labels, the next person on the account cannot tell whether the change was real or only cosmetic.&lt;/p&gt;
&lt;h3 id=&quot;dns-prefetch-vs-preconnect-vs-preload-vs-prefetch-which-hint-to-use&quot;&gt;dns-prefetch vs preconnect vs preload vs prefetch: which hint to use&lt;/h3&gt;
&lt;p&gt;Use one decision table when a client asks which tag belongs in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. The rows match what &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/preconnect-and-dns-prefetch&quot;&gt;web.dev’s preconnect and dns-prefetch article&lt;/a&gt; and the &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/learn/performance/resource-hints&quot;&gt;resource hints learning path&lt;/a&gt; describe. Put the table in the client report once so the team stops arguing over tags that mean different things.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Hint           &lt;/th&gt;&lt;th&gt;What it starts early                                      &lt;/th&gt;&lt;th&gt;Best when                                                                                                     &lt;/th&gt;&lt;th&gt;Avoid when&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dns-prefetch&lt;/code&gt; &lt;/td&gt;&lt;td&gt;DNS lookup only for a cross-origin host                   &lt;/td&gt;&lt;td&gt;You will request that host soon, but it is not among the most urgent early requests                           &lt;/td&gt;&lt;td&gt;You need an early TLS connection for a known critical origin (use &lt;code&gt;preconnect&lt;/code&gt; instead)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;preconnect&lt;/code&gt;   &lt;/td&gt;&lt;td&gt;DNS + TCP + TLS to a cross-origin origin                  &lt;/td&gt;&lt;td&gt;Exact URL is unknown yet, but a critical fetch will hit that origin soon (for example an image CDN)           &lt;/td&gt;&lt;td&gt;You already know the exact critical URL (prefer &lt;code&gt;preload&lt;/code&gt;); or you are opening connections to many origins at once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;preload&lt;/code&gt;      &lt;/td&gt;&lt;td&gt;Fetch of a specific current-document resource             &lt;/td&gt;&lt;td&gt;Late-discovered critical asset for &lt;em&gt;this&lt;/em&gt; page load (LCP image not in HTML, &lt;code&gt;@font-face&lt;/code&gt; file, CSS &lt;code&gt;@import&lt;/code&gt;) &lt;/td&gt;&lt;td&gt;The resource is already discoverable in HTML; or you preload speculative next-page URLs&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;prefetch&lt;/code&gt;     &lt;/td&gt;&lt;td&gt;Low-priority fetch likely needed on a &lt;em&gt;future&lt;/em&gt; navigation &lt;/td&gt;&lt;td&gt;Next-page document or asset with clear probability                                                            &lt;/td&gt;&lt;td&gt;You need the resource for the current LCP; or you confuse it with Speculation Rules prerender&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;dns-prefetch&lt;/code&gt; versus &lt;code&gt;preconnect&lt;/code&gt; is a cost trade-off. &lt;code&gt;preconnect&lt;/code&gt; is stronger for a critical third-party origin and more expensive if overused. Prefer a short list of critical origins for &lt;code&gt;preconnect&lt;/code&gt;, and &lt;code&gt;dns-prefetch&lt;/code&gt; for the rest, then measure. That pairing is the practical answer when someone asks “dns-prefetch vs preconnect.”&lt;/p&gt;
&lt;h3 id=&quot;how-to-preload-the-lcp-image-and-when-preload-is-the-wrong-fix-&quot;&gt;How to preload the LCP image (and when preload is the wrong fix)&lt;/h3&gt;
&lt;p&gt;The first rule for preload LCP work is still discoverability. &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/optimize-lcp&quot;&gt;Optimize Largest Contentful Paint&lt;/a&gt; asks whether the LCP resource appears in the initial HTML so the preload scanner can see it. An &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; with &lt;code&gt;src&lt;/code&gt; or &lt;code&gt;srcset&lt;/code&gt; in the document usually does not need a duplicate preload. A CSS &lt;code&gt;background-image&lt;/code&gt;, an image injected only after JavaScript runs, or a late-discovered responsive candidate often does.&lt;/p&gt;
&lt;p&gt;When you preload, set &lt;code&gt;as=&quot;image&quot;&lt;/code&gt;, match the real URL (or responsive attributes), and use &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt; on the preload. Chrome’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/performance/insights/lcp-discovery&quot;&gt;LCP request discovery&lt;/a&gt; insight still expects high fetch priority on the preload and on the image element when both exist. For responsive heroes, follow web.dev’s caution: use &lt;code&gt;imagesrcset&lt;/code&gt; / &lt;code&gt;imagesizes&lt;/code&gt; on the preload and avoid a bare &lt;code&gt;href&lt;/code&gt; that downloads the wrong fallback on browsers without responsive preload support.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;link
  rel=&quot;preload&quot;
  as=&quot;image&quot;
  href=&quot;/media/hero-1200.webp&quot;
  type=&quot;image/webp&quot;
  fetchpriority=&quot;high&quot;
&amp;gt;
&amp;lt;img
  src=&quot;/media/hero-1200.webp&quot;
  width=&quot;1200&quot;
  height=&quot;675&quot;
  fetchpriority=&quot;high&quot;
  alt=&quot;…&quot;
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the LCP image is already in HTML with &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt; and without &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt;, skip the preload and fix file size, dimensions, or CDN latency instead. Preload is the wrong fix when the real problem is a lazy-loaded hero (see the lazy-loading guide linked above) or a 3 MB unoptimised file. Same-origin delivery still beats a third-party image host plus &lt;code&gt;preconnect&lt;/code&gt; when you can arrange it.&lt;/p&gt;
&lt;h3 id=&quot;preconnect-for-performance-on-cross-origin-origins&quot;&gt;Preconnect for performance on cross-origin origins&lt;/h3&gt;
&lt;p&gt;Preconnect performance gains show up when an important early request must open a new origin before the real URL is known. Classic cases include an image CDN whose path depends on breakpoints, or a font host you will hit after CSS parses. &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect&quot;&gt;Preconnect to required origins&lt;/a&gt; in Lighthouse flags missing connections; it does not mean every third party deserves a tag.&lt;/p&gt;
&lt;p&gt;Keep the list short. Each &lt;code&gt;preconnect&lt;/code&gt; spends time on DNS, TCP, and TLS, and too many compete for limited connections. Prefer same-origin or proxied assets for LCP when the platform allows it. When a cross-origin LCP host is unavoidable, one early &lt;code&gt;preconnect&lt;/code&gt; to that host is often enough, with &lt;code&gt;dns-prefetch&lt;/code&gt; for analytics or chat widgets that load later.&lt;/p&gt;
&lt;p&gt;Cross-origin font files also need CORS-aware loading when you preload them. Pair font &lt;code&gt;preconnect&lt;/code&gt; / &lt;code&gt;preload&lt;/code&gt; with subsetting and &lt;code&gt;font-display&lt;/code&gt; choices from &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/font-subsetting-web-performance-4-tools-reduce-font-file-size-lcp&quot;&gt;Font Subsetting for Web Performance: 4 Tools to Reduce Font File Size and Improve LCP&lt;/a&gt;. Preloading full family files on every template usually wastes more bandwidth than it saves.&lt;/p&gt;
&lt;h3 id=&quot;prefetch-versus-preload-current-page-versus-next-navigation&quot;&gt;Prefetch versus preload: current page versus next navigation&lt;/h3&gt;
&lt;p&gt;Prefetch versus preload is the comparison that most plugin marketing pages blur. &lt;code&gt;preload&lt;/code&gt; is for a resource required to render or complete the &lt;em&gt;current&lt;/em&gt; page load at high priority relative to its type. &lt;code&gt;prefetch&lt;/code&gt; is a low-priority hint for something the user is &lt;em&gt;likely&lt;/em&gt; to need on a later visit. Using &lt;code&gt;prefetch&lt;/code&gt; for the current LCP image gives that image too low a priority. Using &lt;code&gt;preload&lt;/code&gt; for speculative next-page HTML can take bandwidth away from the current hero.&lt;/p&gt;
&lt;p&gt;Document-level &lt;code&gt;rel=prefetch&lt;/code&gt; is also not the same product as Speculation Rules prefetch or prerender, which WordPress and Chrome have been expanding. For CMS plugin behaviour and when speculative loading helps or hurts, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/wordpress-speculation-prerender-plugins-vs-core-web-vitals&quot;&gt;WordPress Speculation and Prerender Plugins vs Core Web Vitals&lt;/a&gt;. Keep classic resource-hint language separate from speculation JSON in client reports so nobody thinks a &lt;code&gt;link rel=prefetch&lt;/code&gt; row is the same as a prerender.&lt;/p&gt;
&lt;h3 id=&quot;font-preload-limits-pair-with-subsetting-not-instead-of-it-&quot;&gt;Font preload limits (pair with subsetting, not instead of it)&lt;/h3&gt;
&lt;p&gt;Fonts defined in CSS &lt;code&gt;@font-face&lt;/code&gt; rules are late-discovered until the stylesheet arrives, so a single WOFF2 preload can help text LCP candidates and shorten the time when text stays invisible. Limits matter more than most theme defaults admit. Preload only the faces used above the fold on that template. Prefer WOFF2. Include &lt;code&gt;crossorigin&lt;/code&gt; when the font is cross-origin so the preload and the CSS request share a cache entry. Do not preload every weight in the brand kit “just in case.”&lt;/p&gt;
&lt;p&gt;If the font file is still hundreds of kilobytes after preload, the real gain is subsetting and fewer families, not more hints. Unused preload warnings in Lighthouse often mean a template preloads a face that page never uses. Agencies should treat font preload as a per-template list in the performance budget, reviewed when themes or design systems change.&lt;/p&gt;
&lt;h3 id=&quot;resource-hint-mistakes-that-hurt-lab-and-field-scores&quot;&gt;Resource-hint mistakes that hurt lab and field scores&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Hint sprawl.&lt;/strong&gt; Ten &lt;code&gt;preconnect&lt;/code&gt; origins and a dozen &lt;code&gt;preload&lt;/code&gt; rows fight the browser’s own prioritisation. Start from the LCP request chain in PageSpeed Insights or Chrome DevTools, then add the minimum hints that close a real gap. If you cannot name the request each hint helps, delete the hint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Preloading what HTML already discovers.&lt;/strong&gt; Duplicate work and unused-preload audits follow. Prefer fixing markup so the scanner sees the image. A redundant preload is not harmless spare capacity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lazy-loading the LCP candidate while preloading something else.&lt;/strong&gt; The hero still waits; the client sees green tips that do not move field LCP. Fix lazy rules first. Only then revisit preload.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Confusing prefetch with preload.&lt;/strong&gt; Next-page speculation belongs in a separate task from current-page LCP. Mixing the words in a status report is how wrong priorities get released. Keep the vocabulary aligned with the decision table above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Untested plugin defaults.&lt;/strong&gt; Many “enable all resource hints” toggles invent origins from third-party scripts. Audit the rendered &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; on revenue and conversion templates, not only the plugin settings screen. A settings screen can look clean while a theme filter still injects tags later.&lt;/p&gt;
&lt;h3 id=&quot;no-vary-search-for-prefetch-and-speculation-short-note-&quot;&gt;No-Vary-Search for prefetch and speculation (short note)&lt;/h3&gt;
&lt;p&gt;When you prefetch or prerender documents, query strings often break cache hits: &lt;code&gt;/product&lt;/code&gt; and &lt;code&gt;/product?utm_source=newsletter&lt;/code&gt; look like different URLs by default. The HTTP &lt;code&gt;No-Vary-Search&lt;/code&gt; response header tells caches which query parameters do not change the response, so a prefetched document can still satisfy a navigation that adds tracking parameters. Speculation Rules can also declare an expected value via &lt;code&gt;expects_no_vary_search&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Treat that as a checklist item beside speculation work (see the WordPress speculation post and MDN’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/No-Vary-Search&quot;&gt;No-Vary-Search&lt;/a&gt; page), not as a replacement for choosing &lt;code&gt;preload&lt;/code&gt; versus &lt;code&gt;prefetch&lt;/code&gt; on the current page. Only ignore parameters that truly leave the HTML unchanged. A deeper Speculation Rules how-to is planned later on the Watcher calendar; keep this section short on purpose.&lt;/p&gt;
&lt;h3 id=&quot;how-to-verify-resource-hints-after-you-deploy-them&quot;&gt;How to verify resource hints after you deploy them&lt;/h3&gt;
&lt;p&gt;Make one change at a time on a labelled URL. Capture mobile and desktop lab rows in PageSpeed Insights or Lighthouse with the same strategy before and after. Confirm the LCP element and request chain still match the story you told the client. Watch for unused preload warnings and for regressions in Total Blocking Time when too many early fetches compete.&lt;/p&gt;
&lt;p&gt;Field Core Web Vitals move on their own clock. A correct preload can still take weeks to show in CrUX. Keep synthetic budgets on the journey URLs that matter, and re-read field categories on a schedule rather than after every deploy. The same logic as synthetic versus real-user monitoring applies here: hints are how you implement the early fetch; dated lab history is how agencies prove that fetch worked.&lt;/p&gt;
&lt;h3 id=&quot;faq-1&quot;&gt;FAQ&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Should I always preload the LCP image?&lt;/strong&gt;&lt;br&gt;
No. Preload when the LCP resource is not discoverable in the initial HTML, or when you need an early high-priority fetch the scanner cannot see yet. If the hero &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; is already in the document with &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt; and without lazy loading, fix file weight and discovery first. Preload is a fix for late discovery, not a default for every template.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is preconnect better than dns-prefetch?&lt;/strong&gt;&lt;br&gt;
For a critical cross-origin origin on the LCP or font path, &lt;code&gt;preconnect&lt;/code&gt; does more (TCP and TLS as well as DNS). It also costs more if you overuse it. Use &lt;code&gt;preconnect&lt;/code&gt; sparingly and &lt;code&gt;dns-prefetch&lt;/code&gt; for lower-priority hosts, then re-test the same URL.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is the difference between prefetch and preload?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;preload&lt;/code&gt; targets a resource for the current page load. &lt;code&gt;prefetch&lt;/code&gt; targets a likely future navigation at lower priority. Do not prefetch the current LCP image when you meant to preload it. If the goal is next-page speed, say so in the task title.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can resource hints fix a poor INP score?&lt;/strong&gt;&lt;br&gt;
Rarely by themselves. INP is about interaction delay and main-thread work. Hints mainly change early network timing for loads and navigations, so keep INP work on scripts and long tasks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do WordPress optimisation plugins handle this safely?&lt;/strong&gt;&lt;br&gt;
Sometimes. Audit the rendered head on key templates. Sitewide “add all hints” modes often create unused preloads and excess preconnects. Prefer explicit lists for LCP and font origins, reviewed per theme update.&lt;/p&gt;
&lt;h3 id=&quot;cta&quot;&gt;CTA&lt;/h3&gt;
&lt;p&gt;Pick the hint from the table before you paste tags into &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. Preload only late-discovered critical assets for the current page, keep preconnect lists short, leave prefetch for likely next navigations, and verify with dated lab runs on the URLs clients actually care about. For portfolio monitoring across many domains after those fixes, start with &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/sign-up&quot;&gt;Apogee Watcher&lt;/a&gt; or run a public check from the homepage tools.&lt;/p&gt;
&lt;h3 id=&quot;references-1&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/learn/performance/resource-hints&quot;&gt;Assist the browser with resource hints&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/preload-critical-assets&quot;&gt;Preload critical assets to improve loading speed&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/preconnect-and-dns-prefetch&quot;&gt;Establish network connections early to improve perceived page speed&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/optimize-lcp&quot;&gt;Optimize Largest Contentful Paint&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/performance/insights/lcp-discovery&quot;&gt;LCP request discovery&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect&quot;&gt;Preconnect to required origins&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/No-Vary-Search&quot;&gt;No-Vary-Search header&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/what-are-core-web-vitals-a-practical-guide-for-2026&quot;&gt;What Are Core Web Vitals? A Practical Guide for 2026&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, CLS: What Each Core Web Vital Means and How to Fix It&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores&quot;&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lazy-loading-lcp-cls-loading-lazy-attribute&quot;&gt;Lazy Loading for LCP and CLS: When to Use&lt;/a&gt; &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lazy-loading-lcp-cls-loading-lazy-attribute&quot;&gt;(and When Not To)&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/font-subsetting-web-performance-4-tools-reduce-font-file-size-lcp&quot;&gt;Font Subsetting for Web Performance: 4 Tools to Reduce Font File Size and Improve LCP&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/wordpress-speculation-prerender-plugins-vs-core-web-vitals&quot;&gt;WordPress Speculation and Prerender Plugins vs Core Web Vitals&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/preload-prefetch-preconnect-resource-hints-faster-core-web-vitals&quot;&gt;Apogee Watcher&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31585/preload-prefetch-and-preconnect-resource-hints-for-faster-core-web-vitals</guid>
<pubDate>Sun, 18 Oct 2026 06:51:44 +0000</pubDate>
</item>
<item>
<title>Lazy Loading for LCP and CLS: When to Use loading=&quot;lazy&quot; (and When Not To)</title>
<link>https://coderlegion.com/30688/lazy-loading-for-lcp-and-cls-when-to-use-loading-lazy-and-when-not-to</link>
<description>&lt;p&gt;Lazy loading images and a fast Largest Contentful Paint (LCP) pull in opposite directions when the same rule is applied to every &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;. Deferring offscreen bytes is usually right, but deferring the hero that PageSpeed Insights later names as LCP is usually wrong. The &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; attribute is only a browser hint for that trade-off. It is not a global “make the site faster” switch that themes and optimisation plugins can sprinkle without review.&lt;/p&gt;
&lt;p&gt;What follows is a decision guide for agencies and product teams: when lazy loading images helps, when it hurts LCP or Cumulative Layout Shift (CLS), and how to prove the change with scheduled lab checks rather than one green Lighthouse run. For the wider image pipeline (formats, sizing, CDN), keep &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores&quot;&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt; open beside this piece. When text paint competes with the hero, &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/font-subsetting-web-performance-4-tools-reduce-font-file-size-lcp&quot;&gt;Font Subsetting for Web Performance: 4 Tools to Reduce Font File Size and Improve LCP&lt;/a&gt; still belongs in the same sprint.&lt;/p&gt;
&lt;h3 id=&quot;what-the-loading-lazy-attribute-does&quot;&gt;What the &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; attribute does&lt;/h3&gt;
&lt;p&gt;The HTML &lt;code&gt;loading&lt;/code&gt; attribute on &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; tells supporting browsers whether to fetch the resource immediately or wait until it is near the viewport. Per &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Lazy_loading&quot;&gt;MDN’s lazy loading guide&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/browser-level-image-lazy-loading&quot;&gt;web.dev’s browser-level image lazy loading article&lt;/a&gt;, &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; is the deferred path and &lt;code&gt;loading=&quot;eager&quot;&lt;/code&gt; (or omitting the attribute for images that default to eager) is the immediate path. Native lazy loading replaced most custom Intersection Observer snippets for ordinary image galleries, yet the browser still decides &lt;em&gt;how far&lt;/em&gt; ahead of the viewport it starts the fetch.&lt;/p&gt;
&lt;p&gt;That nuance matters for agency audits. “We enabled lazy loading” can mean native attributes, a WordPress filter that injects &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; on every attachment, a Shopify theme setting, or a JavaScript library that swaps &lt;code&gt;data-src&lt;/code&gt; after scroll. All of those can defer the LCP candidate if the first screen image is included, so the mechanism belongs in the ticket before anyone blames hosting.&lt;/p&gt;
&lt;p&gt;Native lazy loading is progressive enhancement: older browsers ignore unknown attributes and load images normally. That is fine for bandwidth on modern Chrome and Safari, yet it does not excuse shipping a hero with &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; on the browsers that dominate your CrUX population. Progressive enhancement is not permission to defer the element field users actually paint as LCP.&lt;/p&gt;
&lt;h3 id=&quot;why-lazy-loading-the-lcp-image-hurts-largest-contentful-paint&quot;&gt;Why lazy-loading the LCP image hurts Largest Contentful Paint&lt;/h3&gt;
&lt;p&gt;LCP marks when the largest above-the-fold content element becomes visible. On marketing and commerce pages that element is often a hero image, product photo, or poster frame. If that resource is marked &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt;, the browser may delay the request until layout work suggests the image is “near” the viewport, even though it already is. The result shows up as higher &lt;strong&gt;resource load delay&lt;/strong&gt; in Lighthouse and PageSpeed Insights, and as a worse lab LCP, which Google’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/blog/common-misconceptions-lcp&quot;&gt;common LCP misconceptions&lt;/a&gt; post still flags as a frequent own-goal.&lt;/p&gt;
&lt;p&gt;Search threads for “lazy load LCP” are full of Elementor, WordPress, and theme support tickets for the same pattern: a plugin or theme applied lazy loading sitewide, the logo or banner became LCP, and scores collapsed until someone excluded the first image. Weston Ruter’s comparison demos of lazy-loaded versus eager LCP images make the timing difference visible without arguing theory. Disabling lazy load on the LCP image is a first triage step in those threads, not a last resort after a CDN rewrite.&lt;/p&gt;
&lt;p&gt;The fix is usually boring. Once PageSpeed Insights or Chrome Performance names the LCP element, remove &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; from that image (and any identical mobile/desktop sources in &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;). &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt; fits when you know the LCP URL early; a preload fits only when the markup path cannot put that URL in the initial HTML. Preloading and lazy-loading the same URL fights itself.&lt;/p&gt;
&lt;h3 id=&quot;when-lazy-loading-images-is-the-right-default&quot;&gt;When lazy loading images is the right default&lt;/h3&gt;
&lt;p&gt;Lazy loading images is the right default for content that starts offscreen: article body photos after the fold, related-product grids, footer badges, long category galleries, and comment avatars. Those bytes should not compete with the critical path on first paint. On a twenty-image blog post, native lazy loading can cut early bandwidth sharply on mobile without changing the story the user sees first.&lt;/p&gt;
&lt;p&gt;On retainer sites we treat eager versus lazy as a short policy, not a plugin toggle. Eager (no lazy, or explicit eager) covers the LCP candidate, a logo when it is LCP, the primary above-the-fold product image, and any image inside the first viewport on common breakpoints. Lazy covers everything that requires scroll or a tab change before it matters.&lt;/p&gt;
&lt;p&gt;That policy needs a mobile-width check as well as desktop. An image that looks “below the fold” on a large monitor can sit in the first screen on a phone, and that phone traffic often dominates CrUX. Audits that only run at 1440px tend to lazy-load the wrong assets for the field population.&lt;/p&gt;
&lt;h3 id=&quot;above-the-fold-images-fetchpriority-and-eager-loading&quot;&gt;Above-the-fold images, &lt;code&gt;fetchpriority&lt;/code&gt;, and eager loading&lt;/h3&gt;
&lt;p&gt;“Above the fold” is not a CSS property; it is a judgement about what appears in the initial viewport for your primary breakpoints. When that judgement is wrong, lazy loading above the fold recreates the LCP delay problem even if the CMS labelled the block “content” rather than “hero.” Breakpoints disagree more often than teams expect, especially between a design mockup and a phone-width lab run.&lt;/p&gt;
&lt;p&gt;For the confirmed LCP image, &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; comes off (or &lt;code&gt;loading=&quot;eager&quot;&lt;/code&gt; overrides a stack that injects lazy by default), accurate &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; or aspect-ratio CSS reserve layout space, and &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt; fits when the image is the clear LCP candidate and other resources are not already marked high. An appropriately sized file matters so eager does not mean downloading a 4000px PNG; the image optimisation post linked above covers formats and &lt;code&gt;srcset&lt;/code&gt;. Theme and page-builder defaults often invert that list: every attachment gets lazy, none get fetch priority, and the hero is still a huge JPEG. Attribute policy belongs ahead of another CDN plan. A smaller eager hero usually beats a huge lazy hero on LCP, even when the waterfall looks “optimised” in a plugin dashboard.&lt;/p&gt;
&lt;h3 id=&quot;iframes-video-and-other-lazy-media-caveats&quot;&gt;Iframes, video, and other lazy media caveats&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;loading&lt;/code&gt; attribute also applies to &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;, so below-the-fold embeds (maps, secondary YouTube players, chat widgets) are usually sensible lazy candidates. A first-screen video iframe that is also your LCP or a large layout box can delay paint and still risk CLS if dimensions are missing. A facade (poster image + click-to-load) fits heavy third-party players when the embed is not required for the first view. That pattern pairs with &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/cross-origin-youtube-embeds-and-cls-what-publishers-can-actually-fix&quot;&gt;Cross-Origin YouTube Embeds and CLS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Background images in CSS cannot use &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt;. If the LCP element is a CSS background, attribute fixes will not help; you need a real &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; in the document, or a different LCP strategy. JavaScript lazy libraries that leave &lt;code&gt;src&lt;/code&gt; empty until hydration can also create late discovery worse than native lazy, especially when the library bundle itself is deferred. Video posters and &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements have their own preload behaviour, so “lazy images are on” does not automatically cover posters and iframes. The LCP node type in the trace matters, because a poster frame can win LCP while the checklist only mentions &lt;code&gt;&amp;lt;img loading&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;lazy-loading-and-cls-reserve-space-first&quot;&gt;Lazy loading and CLS: reserve space first&lt;/h3&gt;
&lt;p&gt;Lazy loading does not cause CLS by itself; missing dimensions do. When a lazy image finally loads into a box with no reserved height, the page shifts and CLS rises. That failure mode is easy to miss in a lab run that never scrolls to the image, then appears in field data when users do scroll.&lt;/p&gt;
&lt;p&gt;Lazy loading images still needs intrinsic size hints: &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes, width/height in CMS media metadata, or CSS aspect-ratio on the container. Responsive &lt;code&gt;srcset&lt;/code&gt; still needs a consistent aspect ratio across candidates. If a theme wraps images in a collapsing container until load, the container belongs in the ticket before anyone argues about Core Web Vitals thresholds. Hero images that are eager still need reserved space: eager versus lazy is an LCP timing decision, while dimensioning is a CLS decision, so agencies should treat them as two checklist rows rather than one vague “images” ticket.&lt;/p&gt;
&lt;h3 id=&quot;lab-vs-field-when-lazy-loading-hides-lcp-regressions&quot;&gt;Lab vs field when lazy loading hides LCP regressions&lt;/h3&gt;
&lt;p&gt;A single PageSpeed Insights run on the homepage can look fine after you “enable lazy loading,” especially if the lab viewport and your CMS preview disagree about what is on screen. Field LCP in CrUX or the PageSpeed Insights field section can still worsen when real devices, slower networks, and cookie banners change which element wins LCP. Mobile users may also hit a lazy hero that desktop lab never marked as LCP, so one desktop screenshot is not proof.&lt;/p&gt;
&lt;p&gt;Scheduled lab checks on money URLs (home, category, product, key landing pages) before and after attribute changes, on both mobile and desktop strategies, keep the claim honest. LCP element identity matters more than the score alone. If the LCP node switches from a heading to an image after a deploy, that image’s lazy attribute is the next place to look. For portfolio monitoring across many client sites, Apogee Watcher keeps those lab histories in one place so an attribute change does not vanish into a one-off PDF.&lt;/p&gt;
&lt;p&gt;Lab green and field amber can both be honest, because lab may scroll less, block third parties differently, or use a colder cache. When lazy loading is in the diff, read resource load delay for the LCP URL in the lab diagnostics before you close the ticket. If load delay stays high after “optimisation,” suspect the attribute before you rewrite the media query set.&lt;/p&gt;
&lt;h3 id=&quot;agency-checklist-before-you-ship-lazy-everything-&quot;&gt;Agency checklist before you ship “lazy everything”&lt;/h3&gt;
&lt;p&gt;Before a theme update or “speed plugin” goes to production, a short pass usually pays for itself. The current LCP element and time on mobile and desktop for each money URL set the baseline, then templates and plugin settings get a search for global &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; injection. The LCP candidate (and logo if needed) stays off the lazy list, and width/height or aspect-ratio get confirmed on lazy and eager images alike. Lab checks run again until the LCP element and load delay move the right way; field LCP is watched for the 28-day window after release rather than declared fixed on day one; and the exclusion list is written down so the next plugin install does not re-lazy the hero. That pass is cheaper than a month of “we improved PageSpeed” conversations while CrUX stays amber, and it gives the next developer a written exclusion list instead of tribal knowledge about “the hero must stay eager.” The list belongs in the repository or the retainer runbook so plugin reinstalls do not undo it quietly.&lt;/p&gt;
&lt;h3 id=&quot;faq-2&quot;&gt;FAQ&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Should every image use &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No: lazy loading images is for offscreen content, while the LCP image and other critical above-the-fold images should load eagerly. Sitewide lazy defaults from CMS plugins are a common source of LCP regressions on retainers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; on the LCP image always break field data?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not always, because browsers and viewports differ, but it is a high-risk pattern that Lighthouse and many case studies associate with longer LCP. The LCP candidate usually stays eager unless you have measured no harm on mobile and desktop for that template.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is native lazy loading better than a JavaScript lazy library?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For ordinary images, native lazy loading is usually enough and avoids waiting on a script. Libraries still appear for older patterns or fancy placeholders; they must not leave the LCP &lt;code&gt;src&lt;/code&gt; undiscovered until late JavaScript runs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can lazy loading improve CLS?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Indirectly, only if it reduces contention and you already reserve space. Lazy loading without dimensions often worsens CLS when images pop in during scroll, so sizing belongs ahead of another lazy-loading toggle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What about logos?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If the logo is the LCP element (common on simple brochure sites), it should stay eager. If a large hero is LCP and the logo is small, the logo can follow normal theme defaults, but still reserve space to avoid header shift.&lt;/p&gt;
&lt;h3 id=&quot;ship-eager-heroes-lazy-galleries&quot;&gt;Ship eager heroes, lazy galleries&lt;/h3&gt;
&lt;p&gt;Lazy loading images remains one of the strongest bandwidth defaults on long pages, as long as the LCP image stays eager, dimensions protect CLS, and iframes or video facades are handled on purpose. The &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; attribute is a scalpel for offscreen media, not a blanket for every attachment ID in the CMS. The exclusion list travels with the theme update so the next speed plugin cannot quietly reverse it.&lt;/p&gt;
&lt;p&gt;For format and sizing work around the same LCP element, continue with &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores&quot;&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt;. When font files compete with the hero, use &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/font-subsetting-web-performance-4-tools-reduce-font-file-size-lcp&quot;&gt;Font Subsetting for Web Performance: 4 Tools to Reduce Font File Size and Improve LCP&lt;/a&gt;. To keep attribute changes honest across a client roster, &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/sign-up&quot;&gt;start a free trial&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/check&quot;&gt;run a check&lt;/a&gt; on a money URL before and after you remove lazy from the hero.&lt;/p&gt;
&lt;h3 id=&quot;references-2&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/browser-level-image-lazy-loading&quot;&gt;Browser-level image lazy loading for the web&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Lazy_loading&quot;&gt;Lazy loading&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/blog/common-misconceptions-lcp&quot;&gt;Common misconceptions about how to optimize LCP&lt;/a&gt; (web.dev)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#loading&quot;&gt;HTML attribute: loading&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores&quot;&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/font-subsetting-web-performance-4-tools-reduce-font-file-size-lcp&quot;&gt;Font Subsetting for Web Performance: 4 Tools to Reduce Font File Size and Improve LCP&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://gtmetrix.com/dont-lazy-load-lcp-image.html&quot;&gt;Lighthouse: Don't lazy load Largest Contentful Paint image&lt;/a&gt; (GTmetrix / Lighthouse audit explanation)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/cross-origin-youtube-embeds-and-cls-what-publishers-can-actually-fix&quot;&gt;Cross-Origin YouTube Embeds and CLS: What Publishers Can Actually Fix&lt;/a&gt; (Apogee Watcher)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lazy-loading-lcp-cls-loading-lazy-attribute&quot;&gt;Apogee Watcher&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/30688/lazy-loading-for-lcp-and-cls-when-to-use-loading-lazy-and-when-not-to</guid>
<pubDate>Sun, 11 Oct 2026 07:34:31 +0000</pubDate>
</item>
<item>
<title>Brotli and Gzip Compression: Shrink Text Assets Without Breaking PageSpeed Scores</title>
<link>https://coderlegion.com/29701/brotli-and-gzip-compression-shrink-text-assets-without-breaking-pagespeed-scores</link>
<description>&lt;p&gt;The CDN dashboard shows compression enabled. A host panel lists Brotli as on. A lab run on the priority URL still flags Enable text compression, or the Performance score barely moves while Time to First Byte gets worse after someone raised the Brotli level on dynamic HTML. In our experience the gap is rarely “nobody turned compression on.” It is a mismatch between which responses are compressed, which layer applies &lt;code&gt;Content-Encoding&lt;/code&gt;, and what Lighthouse actually measures on that URL.&lt;/p&gt;
&lt;p&gt;What follows is a delivery guide for teams who already walk DNS, TLS, HTTP, and cache rules in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/network-performance-dns-tls-http-cdn-cache-rules&quot;&gt;Network Performance for Web Teams: DNS, TLS, HTTP, CDN, and Cache Rules&lt;/a&gt;. That piece explains where edge and origin sit on the path to first byte. Here the focus is Brotli compression and gzip for text assets: how teams enable Brotli with a safe fallback, and how to keep PageSpeed Insights and Lighthouse honest after the change. Pair it with &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/cache-control-headers-for-web-performance-cdn-and-browser-caching-that-sticks&quot;&gt;Cache-Control Headers for Web Performance&lt;/a&gt;. Caching decides whether bytes are reused; compression decides how small those bytes are on the first download.&lt;/p&gt;
&lt;h3 id=&quot;what-brotli-and-gzip-change-on-the-response-path&quot;&gt;What Brotli and gzip change on the response path&lt;/h3&gt;
&lt;p&gt;HTTP compression shrinks the body of a response before it travels over the network. The client advertises what it accepts in &lt;code&gt;Accept-Encoding&lt;/code&gt; (commonly &lt;code&gt;br&lt;/code&gt;, &lt;code&gt;gzip&lt;/code&gt;, and &lt;code&gt;deflate&lt;/code&gt;). The server or CDN chooses an encoding and returns &lt;code&gt;Content-Encoding: br&lt;/code&gt; or &lt;code&gt;Content-Encoding: gzip&lt;/code&gt; when it compresses. The browser decompresses before parsing HTML, CSS, or JavaScript. Transfer size drops; the uncompressed size the parser needs does not.&lt;/p&gt;
&lt;p&gt;That distinction matters for Core Web Vitals work. Smaller transfer size can shorten download time for render-blocking CSS and for JavaScript that sits on the critical path. It does not rewrite a slow origin query, a third-party script, or an oversized Largest Contentful Paint image. Compression is a bandwidth and decode trade-off on text responses. It sits beside Time to First Byte and LCP resource priority; it is not a substitute for the fixes in &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/quick-way-to-fix-lcp&quot;&gt;A Quick Way to Fix LCP: Four Changes That Cut Time to Paint&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lighthouse and PageSpeed Insights surface missing compression under audits such as &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-text-compression&quot;&gt;Enable text compression&lt;/a&gt; (&lt;code&gt;uses-text-compression&lt;/code&gt;). Google’s older &lt;a rel=&quot;nofollow&quot; href=&quot;https://developers.google.com/speed/docs/insights/EnableCompression&quot;&gt;Enable Compression&lt;/a&gt; guidance still frames the same idea for agencies reading mixed reports: text resources that benefit from gzip or Brotli should arrive compressed when the client supports it. Gzip compression on the web is still the safety net when Brotli is unavailable on a hop; both belong in the same verification pass.&lt;/p&gt;
&lt;h3 id=&quot;brotli-vs-gzip-for-web-delivery-and-when-gzip-still-wins-&quot;&gt;Brotli vs gzip for web delivery (and when gzip still wins)&lt;/h3&gt;
&lt;p&gt;Brotli versus gzip is not a purity contest. Brotli usually produces smaller text payloads than gzip at comparable quality settings, especially for HTML, CSS, and JavaScript. Gzip is older, universally supported for compressed HTTP responses, and cheap to encode at moderate levels. Most modern browsers prefer Brotli when the server offers &lt;code&gt;br&lt;/code&gt; and the negotiation succeeds.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Dimension &lt;/th&gt;&lt;th&gt;Brotli (&lt;code&gt;br&lt;/code&gt;) &lt;/th&gt;&lt;th&gt;Gzip&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Typical text ratio &lt;/td&gt;&lt;td&gt;Often smaller than gzip at similar effort &lt;/td&gt;&lt;td&gt;Good baseline; larger than Brotli for many CSS/JS bundles&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Encode CPU &lt;/td&gt;&lt;td&gt;Higher at high quality levels on dynamic content &lt;/td&gt;&lt;td&gt;Lower at common levels (for example gzip 4–6)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Browser support for HTTP &lt;/td&gt;&lt;td&gt;Broad for current Chrome, Firefox, Safari, Edge &lt;/td&gt;&lt;td&gt;Universal for compression-capable clients&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Best use &lt;/td&gt;&lt;td&gt;Precompressed static assets; edge or origin for text &lt;/td&gt;&lt;td&gt;Fallback when &lt;code&gt;br&lt;/code&gt; is unavailable; always-on safety net&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Risk if mis-set &lt;/td&gt;&lt;td&gt;High dynamic Brotli quality can inflate TTFB &lt;/td&gt;&lt;td&gt;Double-gzip or gzip on already-compressed binary wastes CPU&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For static fingerprinted files, precompressing at build time (&lt;code&gt;.br&lt;/code&gt; and &lt;code&gt;.gz&lt;/code&gt; siblings) and serving the matching encoding avoids burning origin CPU on every request. For HTML that changes per request, compression at the CDN or reverse proxy with a moderate quality setting usually works better, with gzip kept as the fallback for clients or intermediaries that do not take Brotli. That split (offline high effort for static, moderate online effort for HTML) is what keeps transfer size down without quietly raising Time to First Byte.&lt;/p&gt;
&lt;p&gt;Zstandard (&lt;code&gt;zstd&lt;/code&gt;) appears in some CDN and origin stacks as another encoding. It is useful optional coverage where the edge already supports it. Brotli and gzip remain the baseline pair until client and intermediary support for your traffic mix is proven. Delivery checklists we use with client sites still verify gzip, Brotli, and zstd where the stack claims them.&lt;/p&gt;
&lt;h3 id=&quot;which-responses-to-compress-and-which-to-leave-alone-&quot;&gt;Which responses to compress (and which to leave alone)&lt;/h3&gt;
&lt;p&gt;The responses that benefit are those whose payload is mostly text and is not already in a compressed container. A practical allow-list looks like this, and it is what we expect to match Lighthouse’s text-compression audit when the page is otherwise healthy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;text/html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text/css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text/javascript&lt;/code&gt; / &lt;code&gt;application/javascript&lt;/code&gt; / &lt;code&gt;application/x-javascript&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;application/json&lt;/code&gt; / &lt;code&gt;application/ld+json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;image/svg+xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text/xml&lt;/code&gt; / &lt;code&gt;application/xml&lt;/code&gt; (where XML is not already packaged)&lt;/li&gt;
&lt;li&gt;Often &lt;code&gt;font/woff&lt;/code&gt; is already compressed; woff2 is compressed by design, so wrapping it again rarely helps&lt;/li&gt;
&lt;li&gt;&lt;code&gt;application/wasm&lt;/code&gt; may benefit in some stacks once size and CPU are checked on a representative URL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Brotli or gzip as a blanket over JPEG, PNG, WebP, AVIF, MP4, or other already-compressed media rarely shrinks transfer size and can add latency and CPU. Agencies still hit this when a “compress everything” host preset includes &lt;code&gt;image/*&lt;/code&gt; or when a plugin gzip-filters the whole response stack. The win is smaller text on the wire, not a second envelope around media that is already compressed.&lt;/p&gt;
&lt;p&gt;Partial compression is another common miss. HTML compressed at the edge while CSS and JavaScript miss &lt;code&gt;Content-Encoding&lt;/code&gt; still fails Lighthouse’s text-compression audit for those URLs. The audit looks at individual text resources above a size threshold, not at a single dashboard toggle labelled “Brotli.”&lt;/p&gt;
&lt;h3 id=&quot;how-to-enable-brotli-with-a-gzip-fallback-at-origin-and-cdn&quot;&gt;How to enable Brotli with a gzip fallback at origin and CDN&lt;/h3&gt;
&lt;p&gt;Enabling Brotli only helps when negotiation survives to the browser. Clients send &lt;code&gt;Accept-Encoding&lt;/code&gt; with &lt;code&gt;br&lt;/code&gt; and &lt;code&gt;gzip&lt;/code&gt;. Stacks that prefer Brotli when available, and fall back to gzip without serving identity encoding for large text bodies, clear audits more reliably than a lone dashboard switch.&lt;/p&gt;
&lt;h4 id=&quot;origin-and-reverse-proxy-patterns&quot;&gt;Origin and reverse proxy patterns&lt;/h4&gt;
&lt;p&gt;Common patterns we see work in delivery:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;NGINX with Brotli module.&lt;/strong&gt; Configuration that turns &lt;code&gt;brotli on;&lt;/code&gt; for the MIME types above, sets a moderate &lt;code&gt;brotli_comp_level&lt;/code&gt; for dynamic responses, and keeps &lt;code&gt;gzip on;&lt;/code&gt; with overlapping types so clients without &lt;code&gt;br&lt;/code&gt; still compress. Google’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/google/ngx_brotli&quot;&gt;ngx_brotli&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.nginx.com/nginx/admin-guide/dynamic-modules/brotli/&quot;&gt;NGINX Brotli docs&lt;/a&gt; cover module loading; production still needs a check that the module is loaded, not only present in a staging snippet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apache.&lt;/strong&gt; &lt;code&gt;mod_brotli&lt;/code&gt; / &lt;code&gt;mod_deflate&lt;/code&gt; with explicit &lt;code&gt;AddOutputFilterByType&lt;/code&gt; (or equivalent) for the text MIME list works when filter chains do not compress twice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application middleware.&lt;/strong&gt; Express &lt;code&gt;compression&lt;/code&gt;, Laravel or Rails middleware, and similar helpers often default to gzip. Brotli belongs here only when the library and deployment target support it; otherwise compression at the proxy in front of the app is the cleaner path.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Precompressed static assets.&lt;/strong&gt; Emitting &lt;code&gt;.br&lt;/code&gt; / &lt;code&gt;.gz&lt;/code&gt; at build, mapping &lt;code&gt;Accept-Encoding&lt;/code&gt; to those files, and setting &lt;code&gt;Vary: Accept-Encoding&lt;/code&gt; keeps shared caches from mixing encodings.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;cdn-and-edge&quot;&gt;CDN and edge&lt;/h4&gt;
&lt;p&gt;Many CDNs offer automatic Brotli and gzip for cacheable text. Three facts in the live response matter more than the marketing checkbox, because PageSpeed Insights tests the hostname you give it, not the checkbox label in a vendor UI:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The origin response for HTML, CSS, and JavaScript either arrives compressed or is compressible at the edge without being marked uncacheable for the wrong reason.&lt;/li&gt;
&lt;li&gt;The edge returns &lt;code&gt;Content-Encoding: br&lt;/code&gt; or &lt;code&gt;gzip&lt;/code&gt; on a cold and warm fetch from a client that sends both encodings.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Vary: Accept-Encoding&lt;/code&gt; (or CDN-equivalent vary behaviour) is present so caches store separate variants.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cloudflare and similar platforms document serving Brotli from origin and compression rules. Reading the vendor guide is not enough if an origin &lt;code&gt;Cache-Control: private&lt;/code&gt; or a page rule disables optimisation on the hostname you test in PageSpeed Insights. Compression and caching interact; the Cache-Control post covers HTML versus fingerprinted assets in more depth.&lt;/p&gt;
&lt;h3 id=&quot;fix-lighthouse-enable-text-compression-without-breaking-pagespeed-scores&quot;&gt;Fix Lighthouse “Enable text compression” without breaking PageSpeed scores&lt;/h3&gt;
&lt;p&gt;The Lighthouse audit &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-text-compression&quot;&gt;Enable text compression&lt;/a&gt; fails when text resources are large enough to benefit from compression and arrive without a recognised &lt;code&gt;Content-Encoding&lt;/code&gt;. Clearing the audit means those URLs gain compression on the lab client’s path. It does not mean raising Brotli quality to the maximum on every HTML response.&lt;/p&gt;
&lt;p&gt;A workflow that keeps scores honest usually looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pull the audit URLs from the Lighthouse JSON or PageSpeed Insights diagnostics list (HTML document, CSS, and JavaScript files named in the audit).&lt;/li&gt;
&lt;li&gt;Request each URL with &lt;code&gt;Accept-Encoding: br, gzip&lt;/code&gt; and inspect &lt;code&gt;Content-Encoding&lt;/code&gt;, &lt;code&gt;Content-Type&lt;/code&gt;, and transfer size in DevTools or &lt;code&gt;curl -H &quot;Accept-Encoding: br, gzip&quot; -I&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Turn compression on for the MIME types that failed, while leaving images and already-compressed fonts alone.&lt;/li&gt;
&lt;li&gt;Re-run the same lab profile (same device and throttling) after deploy, watching Performance score and Time to First Byte / LCP, not only the green tick on the audit.&lt;/li&gt;
&lt;li&gt;If Time to First Byte rises while transfer size falls, lower dynamic compression quality or move compression to precompressed static files and edge caching so origin CPU is not on the critical path for every HTML hit.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PageSpeed scores break when teams chase the audit alone: double compression, compressing PDFs or images, or saturating the origin so first byte suffers. The audit is a checklist item. The score reflects the full lab experience. Both belong in the same verification loop.&lt;/p&gt;
&lt;h3 id=&quot;compression-mistakes-that-hurt-ttfb-lcp-or-lab-scores&quot;&gt;Compression mistakes that hurt TTFB, LCP, or lab scores&lt;/h3&gt;
&lt;p&gt;These failure modes show up repeatedly on agency portfolios:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Double compression.&lt;/strong&gt; Origin gzip plus CDN Brotli on an already-encoded body, or a plugin that gzip-filters output already compressed by the proxy. Symptoms include unexpected &lt;code&gt;Content-Encoding&lt;/code&gt; chains, larger transfer sizes, or decode errors. One compression layer per response class, with a clear owner (origin or edge), avoids that class of failure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wrong MIME allow-list.&lt;/strong&gt; Compressing &lt;code&gt;image/jpeg&lt;/code&gt; or skipping &lt;code&gt;text/css&lt;/code&gt; because a preset used outdated type strings. Allow-lists that match what Lighthouse actually requests on the page clear the audit faster than generic host presets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;High Brotli quality on uncached HTML.&lt;/strong&gt; Quality 11 on every HTML response can cost more CPU milliseconds than the download saves on a fast connection. Moderate levels suit dynamic HTML; high effort fits offline precompression of static assets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Missing &lt;code&gt;Vary: Accept-Encoding&lt;/code&gt;.&lt;/strong&gt; Shared caches serve a gzip body to a Brotli-capable client (or the reverse), which produces confusing lab versus browser results and intermittent audit failures.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Assuming the CDN checkbox covers third-party hosts.&lt;/strong&gt; Lighthouse flags text files on your origin and on hosts you control in the waterfall. A script or stylesheet on a tag manager domain you do not configure will keep failing until that host compresses or the file leaves the critical path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Expecting compression alone to fix LCP.&lt;/strong&gt; If the LCP element is a hero image, Brotli on HTML and CSS helps the document and styles, but the image path still dominates. Compression works alongside the LCP levers in the quick-fix guide, not instead of them.&lt;/p&gt;
&lt;h3 id=&quot;verify-content-encoding-on-live-urls-after-every-deploy&quot;&gt;Verify Content-Encoding on live URLs after every deploy&lt;/h3&gt;
&lt;p&gt;Compression belongs in the same habit as Cache-Control: prove it on the live hostname after release, then watch it on a schedule so a platform default does not silently revert.&lt;/p&gt;
&lt;p&gt;A useful checklist per priority URL:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The HTML document and two to three render-blocking CSS/JavaScript URLs from the lab waterfall.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Content-Encoding&lt;/code&gt; of &lt;code&gt;br&lt;/code&gt; or &lt;code&gt;gzip&lt;/code&gt; from a client that sends both in &lt;code&gt;Accept-Encoding&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Transfer size materially smaller than content size for those text files.&lt;/li&gt;
&lt;li&gt;LCP images left alone by the compression layer (no accidental re-encoding).&lt;/li&gt;
&lt;li&gt;A PageSpeed Insights or Lighthouse run before and after so the Enable text compression audit and the Performance score share the same baseline.&lt;/li&gt;
&lt;li&gt;A re-check after CDN rule changes, host panel toggles, and major theme or plugin releases.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Apogee Watcher fits as the scheduled lab layer across client sites. After Brotli and gzip are configured correctly, scheduled re-tests on priority URLs catch a host migration or “optimisation” plugin that drops &lt;code&gt;Content-Encoding&lt;/code&gt; without a ticket. Monitoring layers onto the stack you already run; a single red audit is not a reason to rip out an existing CDN.&lt;/p&gt;
&lt;p&gt;For a starting point on one URL before you standardise a portfolio, &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/check&quot;&gt;apogeewatcher.com/check&lt;/a&gt; is enough. For ongoing multi-site schedules and budgets after compression and cache work, &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/sign-up&quot;&gt;start a trial&lt;/a&gt;. Either path keeps the same question in view: does &lt;code&gt;Content-Encoding&lt;/code&gt; still match what you configured last week?&lt;/p&gt;
&lt;h3 id=&quot;faq-3&quot;&gt;FAQ&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What is Brotli compression on the web?&lt;/strong&gt;&lt;br&gt;
Brotli is a compression format (content coding &lt;code&gt;br&lt;/code&gt;) commonly used for HTTP responses. For web performance it mainly shrinks text assets such as HTML, CSS, and JavaScript when the client advertises support in &lt;code&gt;Accept-Encoding&lt;/code&gt;. MDN’s glossary entry is a short reference; production work still needs header checks on live URLs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Should I enable Brotli or gzip?&lt;/strong&gt;&lt;br&gt;
Both. Brotli when negotiation succeeds, gzip when the client or path cannot use &lt;code&gt;br&lt;/code&gt;. Disabling gzip solely because Brotli exists leaves older clients and some intermediary hops on identity encoding for large text bodies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why does Lighthouse still say Enable text compression?&lt;/strong&gt;&lt;br&gt;
A dashboard toggle is not enough. Individual text resources above the audit threshold must arrive with &lt;code&gt;Content-Encoding: br&lt;/code&gt; or &lt;code&gt;gzip&lt;/code&gt; on the lab request path. Headers and MIME type on each failing URL usually explain the miss faster than another host-panel screenshot.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does Brotli improve Core Web Vitals?&lt;/strong&gt;&lt;br&gt;
It can reduce download time for text on the critical path, which may help LCP and related lab metrics when those files were the bottleneck. It will not fix a slow origin alone or an uncompressed LCP image. Before-and-after runs on the same lab profile show whether the change mattered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can compression make PageSpeed scores worse?&lt;/strong&gt;&lt;br&gt;
Yes. Excessive dynamic compression CPU, double compression, or compressing the wrong asset types can raise Time to First Byte or add work without shrinking useful bytes. Lab tests after every change, with precompression preferred for static files, catch those regressions early.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do I need zstd as well?&lt;/strong&gt;&lt;br&gt;
Only when your CDN and clients benefit from it in production. Brotli and gzip remain the baseline pair for agency portfolios until zstd support is verified for your traffic.&lt;/p&gt;
&lt;p&gt;Compression belongs in the same delivery contract as caching and CDN rules. Naming the layer that owns encoding, limiting it to text that benefits, and verifying &lt;code&gt;Content-Encoding&lt;/code&gt; on live URLs after every deploy keeps the setup honest. When Brotli and gzip are configured that way, Lighthouse’s Enable text compression audit tends to clear without trading away Time to First Byte or inventing a false PageSpeed win.&lt;/p&gt;
&lt;p&gt;Ready to keep compression and Core Web Vitals honest across a client portfolio? &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/sign-up&quot;&gt;Start a free trial of Apogee Watcher&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/check&quot;&gt;run a single URL check&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;references-3&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-text-compression&quot;&gt;Enable text compression (Lighthouse)&lt;/a&gt; (Chrome for Developers)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developers.google.com/speed/docs/insights/EnableCompression&quot;&gt;Enable Compression&lt;/a&gt; (PageSpeed Insights / Google)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Brotli_compression&quot;&gt;Brotli compression (MDN Glossary)&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/gzip_compression&quot;&gt;gzip compression (MDN Glossary)&lt;/a&gt; (MDN)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.nginx.com/nginx/admin-guide/dynamic-modules/brotli/&quot;&gt;NGINX Brotli module&lt;/a&gt; (NGINX Docs)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/google/ngx_brotli&quot;&gt;google/ngx_brotli&lt;/a&gt; (GitHub)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/google/brotli&quot;&gt;google/brotli&lt;/a&gt; (GitHub)&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/network-performance-dns-tls-http-cdn-cache-rules&quot;&gt;Network Performance for Web Teams: DNS, TLS, HTTP, CDN, and Cache Rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/cache-control-headers-for-web-performance-cdn-and-browser-caching-that-sticks&quot;&gt;Cache-Control Headers for Web Performance: CDN and Browser Caching That Sticks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/quick-way-to-fix-lcp&quot;&gt;A Quick Way to Fix LCP: Four Changes That Cut Time to Paint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/brotli-gzip-compression-pagespeed&quot;&gt;Apogee Watcher&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/29701/brotli-and-gzip-compression-shrink-text-assets-without-breaking-pagespeed-scores</guid>
<pubDate>Sun, 04 Oct 2026 06:55:41 +0000</pubDate>
</item>
<item>
<title>A Quick Way to Fix LCP: Four Changes That Cut Time to Paint</title>
<link>https://coderlegion.com/22113/a-quick-way-to-fix-lcp-four-changes-that-cut-time-to-paint</link>
<description>&lt;p&gt;Largest Contentful Paint (LCP) fails when the browser is still waiting on the server, fighting for bandwidth, or blocked on JavaScript before it can paint the biggest thing in the viewport. You do not need a six-week performance programme to move the needle. In our delivery work, four changes cover most urgent LCP regressions: fix Time to First Byte (TTFB), remove competing work from the path to the LCP element, prioritise that element with &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt;, and schedule low-value JavaScript after the &lt;code&gt;load&lt;/code&gt; event. What follows is a practical order of operations, with enough detail to implement without re-reading a full Core Web Vitals textbook.&lt;/p&gt;&lt;p&gt;For background on thresholds and the four LCP sub-parts, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, CLS: What Each Core Web Vital Means and How to Fix It&lt;/a&gt;. For image-specific tuning when the LCP element is a hero photo, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores&quot;&gt;Image Optimisation Strategies for Better LCP Scores&lt;/a&gt;. Both posts go deeper on sub-parts and formats; here we stay focused on the fastest fixes.&lt;/p&gt;&lt;h2 id=&quot;what-is-the-path-to-lcp&quot; class=&quot;scroll-mt-24&quot;&gt;What is the path to LCP?&lt;/h2&gt;&lt;p&gt;LCP is not one timer. It is a chain from first request to final paint of the largest visible element. &lt;a rel=&quot;nofollow&quot; href=&quot;https://web.dev/articles/lcp&quot;&gt;Google’s documentation&lt;/a&gt; breaks the chain into TTFB, resource load delay, resource load duration, and element render delay. The &lt;strong&gt;path to LCP&lt;/strong&gt; is everything the browser does before that element paints: HTML download, discovery of the LCP resource, competing requests, font and script work on the main thread, and layout.&lt;/p&gt;&lt;p&gt;When teams say “LCP is slow but the hero image is only 200 KB,” the bottleneck is usually earlier in the chain. TTFB adds blank time. Icons, analytics, web fonts, and below-the-fold images steal connection slots. JavaScript runs before the browser can commit the LCP paint even after the asset has arrived. The four fixes below map directly to those failure modes.&lt;/p&gt;&lt;h2 id=&quot;step-1-improve-ttfb-time-to-first-byte&quot; class=&quot;scroll-mt-24&quot;&gt;Step 1: Improve TTFB (Time to First Byte)&lt;/h2&gt;&lt;p&gt;TTFB is pure page-blank time. Nothing in the viewport can render until the first byte of HTML arrives. If TTFB is 800 ms on mobile lab tests, every downstream optimisation starts late.&lt;/p&gt;&lt;p&gt;Treat TTFB as a caching and origin problem first:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache database queries&lt;/strong&gt; on CMS and ecommerce routes that build the HTML shell. Object caches (Redis, Memcached) and query result caching cut repeated work on popular templates.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache full pages or page fragments&lt;/strong&gt; at the edge. A CDN or reverse proxy (Cloudflare, Fastly, Varnish, nginx &lt;code&gt;proxy_cache&lt;/code&gt;) should serve anonymous HTML for marketing and category pages where content is not user-specific.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache generated code paths&lt;/strong&gt; where applicable. Opcode caches (OPcache on PHP), template compilation caches, and warmed application caches reduce CPU time per request.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Also check the basics: slow upstream APIs in the critical path, cold serverless instances, and TLS or DNS misconfiguration. TTFB improvements often drop LCP by hundreds of milliseconds without touching front-end assets at all, which makes this step worth doing even when the design team is already compressing heroes.&lt;/p&gt;&lt;p&gt;Run &lt;a rel=&quot;nofollow&quot; href=&quot;https://pagespeed.web.dev/&quot;&gt;PageSpeed Insights&lt;/a&gt; and note TTFB in the diagnostics. If it is high, fix origin and caching before optimising images. Our &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/what-are-core-web-vitals-a-practical-guide-for-2026&quot;&gt;Core Web Vitals guide&lt;/a&gt; lists the “good” LCP band at 2.5 seconds or less in the field; shaving TTFB is the fastest way to buy headroom when you are close to the line.&lt;/p&gt;&lt;h2 id=&quot;step-2-remove-anything-in-the-path-to-lcp-that-matters-less-than-the-lcp-element&quot; class=&quot;scroll-mt-24&quot;&gt;Step 2: Remove anything in the path to LCP that matters less than the LCP element&lt;/h2&gt;&lt;p&gt;Once HTML starts arriving, the browser schedules dozens of requests. Anything that competes with the LCP resource for bandwidth or main-thread time extends &lt;strong&gt;resource load delay&lt;/strong&gt; and &lt;strong&gt;render delay&lt;/strong&gt;. The rule is simple: if it is not required to paint the LCP element, it should not run or download ahead of it.&lt;/p&gt;&lt;h3&gt;Icons and decorative assets&lt;/h3&gt;&lt;p&gt;Favicons, sprite sheets, and small UI icons often sit early in the document or load from high-priority stylesheets. They rarely affect LCP directly, but they consume connections and parser attention. Inline critical icon SVGs only when needed above the fold; otherwise load icon fonts and sprite bundles after the LCP resource is underway or from low-priority async paths.&lt;/p&gt;&lt;h3&gt;Third-party scripts&lt;/h3&gt;&lt;p&gt;Analytics, chat widgets, A/B testing snippets, and personalisation tags are common LCP killers. They execute in the head or early body and block parsing. Audit with the Network panel: sort by start time and see what fires before the LCP image or text block.&lt;/p&gt;&lt;p&gt;Practical moves:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Load tag managers and non-essential vendors &lt;strong&gt;after&lt;/strong&gt; the LCP resource is discoverable (see Step 4 for &lt;code&gt;load&lt;/code&gt;-based scheduling).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Self-host or proxy only what you truly need on first paint.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;For deeper triage patterns, see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/third-party-scripts-performance-worst-offenders&quot;&gt;Third-Party Scripts and Performance: How to Identify and Fix the Worst Offenders&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Below-the-fold images&lt;/h3&gt;&lt;p&gt;Lazy-loading is correct for content lower on the page, but never lazy-load the LCP candidate. Conversely, do not let below-the-fold &lt;code&gt;&lt;img src=&quot;src&quot; alt=&quot;image&quot;&gt;&lt;/code&gt; tags without &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; sit in the head of the queue with &lt;code&gt;fetchpriority&lt;/code&gt; defaults that compete with the hero. Ensure decorative and content images that are not LCP use lazy loading and lower priority so the hero wins the network race.&lt;/p&gt;&lt;h3&gt;Fonts that are not needed for the LCP element&lt;/h3&gt;&lt;p&gt;Web fonts are often requested from CSS before the LCP image is even parsed. If the LCP element is a photograph, decorative display fonts do not need to block the chain. If the LCP element is a headline, only the weights used in that headline need early loading.&lt;/p&gt;&lt;p&gt;The goal is not “delay until interaction” tricks that hide text until a user taps. The goal is &lt;strong&gt;enqueue order&lt;/strong&gt;: make sure font files for secondary UI copy enter the pipeline &lt;strong&gt;after&lt;/strong&gt; the LCP resource is requested and ideally after it has started downloading. Techniques include splitting &lt;code&gt;@font-face&lt;/code&gt; rules into non-critical stylesheets loaded later, subsetting fonts (&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/font-subsetting-web-performance-4-tools-reduce-font-file-size-lcp&quot;&gt;font subsetting guide&lt;/a&gt;), and using system font stacks for non-LCP text on first paint.&lt;/p&gt;&lt;h2 id=&quot;step-3-prioritise-the-lcp-element-with-fetchpriorityhigh&quot; class=&quot;scroll-mt-24&quot;&gt;Step 3: Prioritise the LCP element with fetchpriority=&quot;high&quot;&lt;/h2&gt;&lt;p&gt;Browsers schedule requests with heuristics. Hero images discovered late in HTML or hidden behind CSS may get default priority while less important assets jump ahead. The &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/fetchpriority&quot;&gt;&lt;code&gt;fetchpriority&lt;/code&gt;&lt;/a&gt; attribute lets you mark what matters.&lt;/p&gt;&lt;p&gt;For an image LCP element:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;/code&gt;&lt;/pre&gt;&lt;img src=&quot;/media/hero.avif&quot; alt=&quot;Product range on a workbench&quot; width=&quot;1200&quot; height=&quot;675&quot;&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;Pair with &lt;code&gt;&lt;link rel=&quot;preload nofollow&quot; href=&quot;/media/hero.avif&quot;&gt;&lt;/code&gt; in &lt;code&gt;&lt;/code&gt; when the LCP image is known at build time and appears late in the markup. Preload is not a substitute for fixing TTFB or removing competing scripts, but it removes discovery delay when the hero sits below inline styles or markup generated by JavaScript.&lt;/p&gt;&lt;p&gt;Do not set &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt; on everything. If every image is high priority, none are. Reserve it for the single LCP candidate PSI reports in Lighthouse diagnostics.&lt;/p&gt;&lt;p&gt;For text or video LCP elements, the same principle applies: ensure the resource that feeds the largest paint is discoverable early and not deprioritised by lazy attributes or late injection.&lt;/p&gt;&lt;h2 id=&quot;step-4-schedule-less-important-javascript-after-the-load-event&quot; class=&quot;scroll-mt-24&quot;&gt;Step 4: Schedule less important JavaScript after the load event&lt;/h2&gt;&lt;p&gt;Even when the LCP asset has downloaded, element render delay can balloon if the main thread is busy executing JavaScript. Parsing, compilation, and long tasks defer layout and paint, which is why deferral belongs in the same checklist as caching and fetch priority.&lt;/p&gt;&lt;p&gt;&lt;code&gt;defer&lt;/code&gt; and &lt;code&gt;async&lt;/code&gt; help for scripts that must run before interaction, but many apps bundle analytics, carousels, and enhancement code that can wait until the page has fully loaded. The &lt;code&gt;load&lt;/code&gt; event fires when the document and its subresources (images, stylesheets) have finished loading. Scheduling non-critical work there keeps the main thread freer while LCP is still forming.&lt;/p&gt;&lt;p&gt;Example pattern:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;br&gt;
  window.addEventListener('load', function () {
&lt;code&gt;requestIdleCallback(function () {
  initNonCriticalWidgets();
  loadDeferredAnalytics();
}, { timeout: 2000 });
&lt;/code&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  });&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;&lt;p&gt;Use &lt;code&gt;requestIdleCallback&lt;/code&gt; where supported so you do not immediately replace one long task with another. Framework-specific code splitting (dynamic &lt;code&gt;import()&lt;/code&gt; on &lt;code&gt;load&lt;/code&gt; or on first interaction) achieves the same outcome: the LCP element paints before megabytes of client-side routing and chart libraries execute.&lt;/p&gt;&lt;p&gt;This is distinct from deferring fonts until interaction, which can harm readability. Here we defer JavaScript functions that do not affect first paint: heatmaps, chat bubbles, personalisation hooks, and secondary carousels below the hero.&lt;/p&gt;&lt;h2 id=&quot;a-one-hour-lcp-fix-workflow&quot; class=&quot;scroll-mt-24&quot;&gt;A one-hour LCP fix workflow&lt;/h2&gt;&lt;p&gt;Use this sequence when you have a red LCP on a priority URL and limited time:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Identify the LCP element&lt;/strong&gt; in PageSpeed Insights or Lighthouse (Diagnostics → LCP element).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Record TTFB&lt;/strong&gt; on mobile lab. If it is above ~600 ms, open caching and origin tickets first.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Waterfall audit&lt;/strong&gt;: list every request and script that starts before the LCP resource. Remove or postpone icons, third parties, lazy-competing images, and non-LCP fonts.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt;&lt;/strong&gt; (and preload if needed) on the LCP node only.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Move non-critical JS&lt;/strong&gt; to &lt;code&gt;load&lt;/code&gt; + idle callbacks; retest.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set an LCP budget&lt;/strong&gt; in your monitoring tool so the fix survives the next deploy. See &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/performance-budget-thresholds-template&quot;&gt;Performance Budget Thresholds Template&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Agencies managing many client homepages and landers should run mobile and desktop lab tests on the same URL after each change. One-off PSI tabs miss regressions when a plugin reintroduces a head script. &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/pagespeed-insights-vs-automated-monitoring-when-manual-checks-arent-enough&quot;&gt;PageSpeed Insights vs automated monitoring&lt;/a&gt; explains why scheduled tests and alerts matter once the quick fix ships.&lt;/p&gt;&lt;h2 id=&quot;what-these-four-steps-do-not-replace&quot; class=&quot;scroll-mt-24&quot;&gt;What these four steps do not replace&lt;/h2&gt;&lt;p&gt;These changes target the &lt;strong&gt;delivery path&lt;/strong&gt; to LCP. They do not replace image compression, responsive &lt;code&gt;srcset&lt;/code&gt;, CDN tuning, or server-side rendering when the LCP element itself is too large or injected only after client-side hydration. When the LCP element is an image, combine this checklist with the &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores&quot;&gt;image optimisation guide&lt;/a&gt;. When third parties dominate the waterfall, the &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/third-party-scripts-performance-worst-offenders&quot;&gt;third-party scripts post&lt;/a&gt; goes deeper on vendor policy.&lt;/p&gt;&lt;p&gt;LCP also differs between mobile and desktop strategies. A fix on one may not carry to the other if different heroes or ad slots apply. Monitor both; see &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/mobile-vs-desktop-core-web-vitals-monitoring-both&quot;&gt;Mobile vs Desktop Core Web Vitals&lt;/a&gt;.&lt;/p&gt;&lt;h2 class=&quot;scroll-mt-24&quot;&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Should I fix TTFB or the LCP image first?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Fix TTFB first when it is high. Blank time before HTML cannot be recovered by compressing a hero image. If TTFB is already healthy, focus on the path to LCP and the LCP resource itself.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Does fetchpriority replace preload?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;No. &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt; adjusts priority once the browser discovers the resource. Preload starts discovery earlier when the URL is known at build time. Use both on image heroes that appear late in the document.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Is lazy-loading the LCP element ever correct?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;No. Never lazy-load the element PageSpeed Insights reports as LCP. Lazy-load below-the-fold images only.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Why defer JavaScript to load instead of using defer on every script?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The &lt;code&gt;defer&lt;/code&gt; attribute preserves execution order before &lt;code&gt;DOMContentLoaded&lt;/code&gt; for scripts that still run during the critical path. Analytics, widgets, and enhancement bundles that do not affect first paint can wait until &lt;code&gt;load&lt;/code&gt;, which reduces main-thread contention while LCP is still forming.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How do I know the fix worked?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Re-run PageSpeed Insights on the same URL and strategy (mobile vs desktop). Compare LCP time and the filmstrip. For production confidence, schedule lab tests with budgets in Apogee Watcher so the next theme or tag-manager change triggers an alert if LCP drifts back above your threshold.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Can Apogee Watcher fix LCP automatically?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;No. Watcher schedules PageSpeed lab tests, stores LCP and other vitals over time, and emails you when budgets breach. You still implement caching, prioritisation, and script deferral in the codebase; Watcher tells you when those fixes slip on priority URLs across client sites.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;TTFB, a clear path to the LCP element, &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt;, and JavaScript deferred until after &lt;code&gt;load&lt;/code&gt; are the four changes we reach for first when LCP is red and the release window is small. Ship them in that order, re-test on mobile lab, then lock the win with budgets and scheduled monitoring so the metric stays green after the next deploy. &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/sign-up&quot;&gt;Start a free Apogee Watcher account&lt;/a&gt; to track LCP on priority URLs with mobile and desktop schedules and vitals budgets, or run a &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/check&quot;&gt;free domain PageSpeed check&lt;/a&gt; before you change caching or script order.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22113/a-quick-way-to-fix-lcp-four-changes-that-cut-time-to-paint</guid>
<pubDate>Thu, 09 Jul 2026 12:39:00 +0000</pubDate>
</item>
<item>
<title>Font Subsetting for Web Performance: 4 Tools to Reduce Font File Size and Improve LCP</title>
<link>https://coderlegion.com/19415/font-subsetting-for-web-performance-4-tools-to-reduce-font-file-size-and-improve-lcp</link>
<description>&lt;p&gt;In web development, every millisecond on the critical path matters. Typography is part of your visual identity, yet a single self-hosted family can add hundreds of kilobytes before the browser paints the hero line clients actually see. That cost often shows up as slower &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;First Contentful Paint (FCP)&lt;/a&gt; and a worse &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/tag/lcp&quot;&gt;Largest Contentful Paint (LCP)&lt;/a&gt; when the LCP element is a headline set in a custom face.&lt;/p&gt;&lt;p&gt;Font subsetting is the practical fix: ship only the characters (glyphs) each page or component needs instead of entire typefaces built for every language and symbol you will never render.&lt;/p&gt;&lt;h2&gt;What font subsetting is&lt;/h2&gt;&lt;p&gt;A typical desktop font file contains thousands of glyphs: Latin extended, Cyrillic, ligatures, numerals, punctuation, and symbols you may never use on a marketing site. When you &lt;code&gt;@font-face&lt;/code&gt; that file or pull it from a CDN, the browser still has to download and parse the whole package unless you split it.&lt;/p&gt;&lt;p&gt;Subsetting creates a smaller font file that includes a defined subset of Unicode code points. Examples:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;A display font used only on one H1 might need fewer than 40 characters.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;A Latin-only blog body font does not need CJK tables on every article.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;UI labels in English can omit unused weights and scripts.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The browser downloads less data, spends less time decoding, and can apply the face sooner. You keep the look; you drop the dead weight.&lt;/p&gt;&lt;h2&gt;When font subsetting improves web font performance and LCP&lt;/h2&gt;&lt;p&gt;Subsetting pays off fastest in these cases:&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Situation&lt;/th&gt;&lt;th&gt;Why subsetting helps&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Display or hero typography&lt;/td&gt;&lt;td&gt;Few unique characters, high visual impact, often on the LCP text node&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Single-language sites&lt;/td&gt;&lt;td&gt;Remove unused scripts and diacritic ranges you do not publish&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Icon or logo fonts misused as full fonts&lt;/td&gt;&lt;td&gt;Replace with SVG where possible; subset if you must keep a font icon set&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Multiple weights loaded globally&lt;/td&gt;&lt;td&gt;Subset per weight, or load weights only on routes that need them&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;It is lower priority when you already use a system font stack for body copy and only load one small variable font with modern compression. Still measure: “small” on disk is not always small on a slow mobile connection.&lt;/p&gt;&lt;p&gt;Pair subsetting with loading discipline: &lt;code&gt;font-display: swap&lt;/code&gt; or &lt;code&gt;optional&lt;/code&gt;, preload only the file that blocks the hero, and avoid loading six weights site-wide because the brand guide lists them. Our &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/image-optimisation-strategies-better-lcp-scores&quot;&gt;image optimisation strategies for better LCP&lt;/a&gt; guide covers the image side of the same paint problem; fonts are the other half of many hero templates.&lt;/p&gt;&lt;h2&gt;Font subsetting example: hero display copy without the full font file&lt;/h2&gt;&lt;p&gt;Imagine a campaign landing page with one H1 in a distinctive display face: “Summer sale ends Sunday”. The full commercial font might be 180 KB of WOFF2 per weight. The string uses letters, a space, and basic punctuation: perhaps 28 glyphs.&lt;/p&gt;&lt;p&gt;Subsetting to those glyphs (plus a few extras you reserve for CMS edits, such as &lt;code&gt;0123456789&lt;/code&gt; and &lt;code&gt;-%&lt;/code&gt;) might produce a file under 15 KB. Same aesthetics on the title; far less work for the network and font loader on first visit.&lt;/p&gt;&lt;p&gt;Always keep a slightly wider subset than the literal string if editors can change copy without redeploying. A common pattern is “characters used on site” plus a safety buffer of numerals and common punctuation, or a per-locale subset file.&lt;/p&gt;&lt;h2&gt;Four tools for font subsetting&lt;/h2&gt;&lt;p&gt;You do not need to hand-edit binary tables for most projects. These four tools cover the usual workflows.&lt;/p&gt;&lt;h3&gt;Google Fonts&lt;/h3&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fonts.google.com/&quot;&gt;Google Fonts&lt;/a&gt; hosts families with many axes and scripts. When you embed through the Google Fonts CSS API, you can limit what Google serves:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Use the &lt;code&gt;text=&lt;/code&gt; parameter to request only the characters in a string (useful for fixed hero copy).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Choose only the weights and styles you need in the embed code generator.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Prefer &lt;code&gt;display=swap&lt;/code&gt; (or &lt;code&gt;optional&lt;/code&gt; where appropriate) so text stays visible while the file loads.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Self-hosting a Google Font download is also valid: download the family, subset locally, and serve WOFF2 from your own CDN for stricter cache control.&lt;/p&gt;&lt;h3&gt;Font Squirrel Webfont Generator&lt;/h3&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.fontsquirrel.com/tools/webfont-generator&quot;&gt;Font Squirrel’s Webfont Generator&lt;/a&gt; is the familiar upload-and-convert workflow. Upload your source (check your licence allows web embedding), choose “Expert” mode, and define custom subsets: Unicode ranges, specific glyphs, or language presets. It outputs WOFF2/WOFF kits with a starter &lt;code&gt;@font-face&lt;/code&gt; block.&lt;/p&gt;&lt;p&gt;Good for agency teams without a font toolchain in CI: one-off subsets for a client launch, then store the outputs in the repo or asset pipeline.&lt;/p&gt;&lt;h3&gt;Everything Fonts Subsetter&lt;/h3&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://everythingfonts.com/subsetter&quot;&gt;Everything Fonts Subsetter&lt;/a&gt; accepts uploaded TTF/OTF/WOFF files and builds a reduced file from the characters you paste or select. Useful when you already know the exact glyph list from a design export or when you are trimming an existing self-hosted file after an audit.&lt;/p&gt;&lt;h3&gt;FontForge&lt;/h3&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fontforge.org/&quot;&gt;FontForge&lt;/a&gt; is desktop software for creating and editing fonts. Use it when you need precise control: merge subsets, remove tables, or build a custom subset for a product name baked into a brand face. The learning curve is steeper than a web generator, but it is the right tool when the font is yours to modify or when legal subsetting must be documented for the client.&lt;/p&gt;&lt;h2&gt;How to implement font subsets (&lt;code&gt;@font-face&lt;/code&gt;, &lt;code&gt;unicode-range&lt;/code&gt;, &lt;code&gt;font-display&lt;/code&gt;)&lt;/h2&gt;&lt;p&gt;After you have a smaller file, wire it so the browser does not download the old full font by mistake.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;@font-face {
  font-family: &quot;Brand Display&quot;;
  src: url(&quot;/fonts/brand-display-hero-subset.woff2&quot;) format(&quot;woff2&quot;);
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0020-007F;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;unicode-range&lt;/code&gt; tells the browser to skip downloading this file for characters outside the range. You can split one family into multiple files (Latin hero, Latin body, numerals-only) so each page loads only what it needs.&lt;/p&gt;&lt;p&gt;For variable fonts, subsetting is trickier but still worthwhile on high-traffic templates. Test on real devices: some older browsers handle &lt;code&gt;unicode-range&lt;/code&gt; plus variable fonts differently than a static WOFF2 subset.&lt;/p&gt;&lt;p&gt;Document subsets in your client handover: which file applies to which template, and how to regenerate when marketing changes the hero string.&lt;/p&gt;&lt;h2&gt;Reduce font file size: less data per page view&lt;/h2&gt;&lt;p&gt;Subsetting is a technical optimisation first. Smaller font files mean less data over the wire per page view. On a site with 50 000 monthly sessions and a 150 KB font removed from the critical path, you avoid gigabytes of transfer over a year without changing the design.&lt;/p&gt;&lt;p&gt;That matters for:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Mobile users on metered or weak connections&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;CDN and origin egress costs at scale&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Battery and CPU spent decoding fonts that never render&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We avoid treating that as vague “eco” marketing. The measurable claim is simpler: you sent fewer bytes for the same page. If sustainability reporting matters to your client, subsetting is one line item next to image compression and script audits.&lt;/p&gt;&lt;h2&gt;How to verify LCP and FCP after font subsetting&lt;/h2&gt;&lt;p&gt;Subsetting is not done when the file size looks smaller in Finder. Verify in the browser and in your monitoring rhythm.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Network panel:&lt;/strong&gt; Confirm the subset WOFF2 is requested (not the legacy full file). Check transfer size and that the request sits early enough for the hero.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;PageSpeed Insights or Lighthouse:&lt;/strong&gt; Compare FCP and LCP before and after on the same URL and throttling profile. Lab scores move for many reasons; keep one change per deploy when you are proving cause.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Filmstrip or trace:&lt;/strong&gt; Ensure the hero text does not flash invisible for long periods. If &lt;code&gt;font-display: swap&lt;/code&gt; causes a large layout shift when the custom face arrives, fix CLS separately (reserved space, fallback metrics).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Production monitoring:&lt;/strong&gt; If you run &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/how-to-set-up-automated-pagespeed-monitoring-for-multiple-sites&quot;&gt;automated PageSpeed monitoring&lt;/a&gt;, add the template to a &lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/performance-budget-thresholds-template&quot;&gt;performance budget&lt;/a&gt; so a future CMS or plugin change does not reintroduce the full font on every page.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Agencies maintaining many sites benefit from the same loop as images: fix the asset, prove it in lab, then watch scheduled tests so the regression does not return quietly on the next theme update.&lt;/p&gt;&lt;p&gt;Pick one high-traffic URL where the LCP node is text in a custom font. List the characters that can appear in that block (or export copy from the CMS). Generate a subset with Font Squirrel or Everything Fonts, deploy with &lt;code&gt;font-display: swap&lt;/code&gt;, and re-run PSI. If LCP improves, roll the same pattern to other display templates and document the glyph list for the client.&lt;/p&gt;&lt;h2&gt;Common font subsetting mistakes&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subsetting too aggressively&lt;/strong&gt; so editors cannot type an em dash or an accented character without tofu squares.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Loading both subset and full font&lt;/strong&gt; because an old enqueue line was left in WordPress or the tag manager.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subsetting body fonts but still loading five weights&lt;/strong&gt; on pages that use one weight.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ignoring licensing&lt;/strong&gt;; not every foundry permits subsetting or self-hosting. Read the EULA before Font Squirrel or FontForge exports go to production.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skipping fallbacks&lt;/strong&gt;; use a similar system stack in &lt;code&gt;font-family&lt;/code&gt; so text stays readable if the subset fails to load.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Typography should not be the reason a fast layout scores poorly on paint metrics. Subsetting keeps the brand face while respecting the budget the network actually has.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/sign-up&quot;&gt;Create a free account&lt;/a&gt;&lt;/strong&gt; to track LCP and FCP across client sites with scheduled PageSpeed tests and performance budgets.&lt;/p&gt;&lt;h2&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Does font subsetting affect SEO?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Not directly. Search engines care about experience signals and crawlability. Faster paint and stable layout support the page experience story; subsetting is one input, not a ranking lever on its own.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Can I subset Google Fonts without self-hosting?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Yes, partially. The CSS API &lt;code&gt;text=&lt;/code&gt; and family/axis parameters reduce what Google sends. For maximum control and caching, download and self-host a subset you generated.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Will subsetting break translations?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;It can if you subset for English only and later add a Greek or Japanese locale. Plan per-locale subset files or a wider subset for multilingual templates.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;WOFF2 only, or still ship WOFF?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;For modern browsers in 2026, WOFF2 alone is usually enough. Keep WOFF only if you must support legacy clients named in the client’s browser support policy.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How does subsetting compare to using a system font stack?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;System fonts add zero webfont bytes. Subsetting is the middle path when brand guidelines require a custom face but you refuse to ship an entire foundry file on every route.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Should I subset icon fonts?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Prefer SVG icons. If you remain on an icon font, subset to the icons in use or migrate to inline SVG to remove font decoding from the critical path entirely.&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/19415/font-subsetting-for-web-performance-4-tools-to-reduce-font-file-size-and-improve-lcp</guid>
<pubDate>Tue, 02 Jun 2026 10:47:00 +0000</pubDate>
</item>
<item>
<title>Image Optimisation Strategies for Better LCP Scores</title>
<link>https://coderlegion.com/14052/image-optimisation-strategies-for-better-lcp-scores</link>
<description>&lt;p&gt;On many marketing and product pages, &lt;strong&gt;Largest Contentful Paint (LCP)&lt;/strong&gt; is not abstract. It is a hero photograph, a product shot, or a full-width banner. The metric tracks when that largest visible element finishes rendering; if the element is an image, your optimisation work is mostly &lt;strong&gt;bytes, dimensions, and discovery order&lt;/strong&gt;—not another round of “general speed tips”.&lt;/p&gt;&lt;p&gt;This guide assumes you already know what LCP measures. If you need the full picture first, read &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/what-are-core-web-vitals-a-practical-guide-for-2026&quot;&gt;What Are Core Web Vitals? A Practical Guide for 2026&lt;/a&gt; and &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, CLS: What Each Core Web Vital Means and How to Fix It&lt;/a&gt;. Here we go deep on &lt;strong&gt;image-specific&lt;/strong&gt; strategies that move LCP toward the “good” band (≤ 2.5 seconds in the field), and how to pair them with &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/the-complete-guide-to-performance-budgets-for-web-teams&quot;&gt;performance budgets&lt;/a&gt; so improvements stick.&lt;/p&gt;&lt;h2&gt;Start by identifying the real LCP element&lt;/h2&gt;&lt;p&gt;You cannot optimise “the page” in the abstract. LCP is tied to &lt;strong&gt;one&lt;/strong&gt; element in the viewport. In PageSpeed Insights or Lighthouse, open the diagnostics and note which node is reported as LCP—often an &lt;code&gt;&lt;img src=&quot;src&quot; alt=&quot;image&quot;&gt;&lt;/code&gt;, sometimes a text block or a background.&lt;/p&gt;&lt;p&gt;If the tool points at an image:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Confirm the URL&lt;/strong&gt; you are actually serving (CDN vs origin, &lt;code&gt;srcset&lt;/code&gt; winner, and any CMS transforms).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Check the file size&lt;/strong&gt; after compression. A 2.5 MB hero on a 360 px wide phone viewport is a sizing problem first, not a format problem.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Trace load order&lt;/strong&gt;: is something else blocking discovery (late CSS, client-rendered markup, or a lazy attribute on the hero)?&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Skipping this step is how teams ship a perfect WebP pipeline and still fail LCP because the LCP element was a different image—or text—than they assumed.&lt;/p&gt;&lt;h2&gt;Pick modern formats and tune quality deliberately&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;AVIF&lt;/strong&gt; usually beats &lt;strong&gt;WebP&lt;/strong&gt; on file size at comparable visual quality; &lt;strong&gt;WebP&lt;/strong&gt; still beats most &lt;strong&gt;JPEG&lt;/strong&gt; for photos. The practical approach for 2026:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Serve &lt;strong&gt;AVIF&lt;/strong&gt; with &lt;strong&gt;WebP&lt;/strong&gt; or &lt;strong&gt;JPEG&lt;/strong&gt; fallbacks using &lt;code&gt;&lt;picture&gt;&lt;/picture&gt;&lt;/code&gt; &lt;strong&gt;or&lt;/strong&gt; rely on your CDN’s automatic format negotiation if you trust its tests.&lt;/li&gt;&lt;li&gt;Avoid shipping a single giant JPEG “because it works everywhere” unless you have measured that the conversion pipeline genuinely cannot run yet.&lt;/li&gt;&lt;li&gt;For illustrations with flat colour, &lt;strong&gt;SVG&lt;/strong&gt; or optimised &lt;strong&gt;PNG&lt;/strong&gt; can win; for large photographic heroes, raster formats dominate.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Quality settings are not universal.&lt;/strong&gt; A quality of 75 in one encoder is not the same as 75 in another. Pick a default (for example AVIF at a sensible quantiser, WebP at 75–80), then &lt;strong&gt;visually compare&lt;/strong&gt; at real display widths. Automated tools help, but a human glance at banding on skies and skin tones still catches regressions.&lt;/p&gt;&lt;p&gt;When you change format, &lt;strong&gt;re-measure LCP&lt;/strong&gt; on the same URL. Lab scores can move for reasons unrelated to user-perceived quality, so keep before/after filmstrips or screenshots for stakeholders.&lt;/p&gt;&lt;h2&gt;Match dimensions to rendered size, not to the asset library&lt;/h2&gt;&lt;p&gt;LCP often fails because the browser decodes a &lt;strong&gt;4000 px&lt;/strong&gt; image into a &lt;strong&gt;400 px&lt;/strong&gt; slot. Responsive design does not mean “one huge master file for all breakpoints”.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Export or generate variants at &lt;strong&gt;the maximum CSS width&lt;/strong&gt; they will occupy, per breakpoint, with a small margin for DPR (device pixel ratio). A 2× retina asset should be roughly &lt;strong&gt;2× the CSS pixels&lt;/strong&gt;, not 5× “for safety”.&lt;/li&gt;&lt;li&gt;Strip metadata you do not need; it is wasted bytes on every request.&lt;/li&gt;&lt;li&gt;If your CMS offers “automatic resizing”, verify the &lt;strong&gt;actual&lt;/strong&gt; output dimensions in Network, not the checkbox in the admin UI.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you only do one thing after reading this section: &lt;strong&gt;open DevTools → Network&lt;/strong&gt;, click the LCP image, and compare &lt;strong&gt;Intrinsic size&lt;/strong&gt; (natural width/height) to &lt;strong&gt;Rendered size&lt;/strong&gt;. If the intrinsic side is many times larger than rendered, fix that before touching anything else.&lt;/p&gt;&lt;h2&gt;Use &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; so the browser picks a sane file&lt;/h2&gt;&lt;p&gt;Giving the browser a &lt;strong&gt;range&lt;/strong&gt; of widths beats a single &lt;code&gt;src&lt;/code&gt; for almost all content images.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;srcset&lt;/code&gt;&lt;/strong&gt; lists candidate widths or descriptors (&lt;code&gt;480w&lt;/code&gt;, &lt;code&gt;800w&lt;/code&gt;, …).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;sizes&lt;/code&gt;&lt;/strong&gt; tells the browser how wide the image will be &lt;strong&gt;in the layout&lt;/strong&gt; at different viewport widths, so it can pick the right candidate &lt;strong&gt;before&lt;/strong&gt; downloading the wrong one.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Common mistakes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;sizes=&quot;100vw&quot;&lt;/code&gt;&lt;/strong&gt; on an image that is only half the layout width—so the browser pulls an unnecessarily large file.&lt;/li&gt;&lt;li&gt;Omitting &lt;strong&gt;&lt;code&gt;sizes&lt;/code&gt;&lt;/strong&gt; when using &lt;code&gt;w&lt;/code&gt; descriptors, which can lead to poor selections.&lt;/li&gt;&lt;li&gt;Using &lt;strong&gt;&lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt;&lt;/strong&gt; on an image that is &lt;strong&gt;above the fold&lt;/strong&gt; and is your LCP element. The browser may defer work you needed immediately.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For a full-width hero, &lt;code&gt;sizes=&quot;100vw&quot;&lt;/code&gt; is often correct. For a card grid, describe the column width at each breakpoint. MDN’s documentation on responsive images is worth bookmarking for copy-paste patterns you can adapt.&lt;/p&gt;&lt;h2&gt;Loading order: preload, priority, and lazy boundaries&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Preload&lt;/strong&gt; the LCP image when you know the URL early in the document:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;link rel=&quot;preload nofollow&quot; href=&quot;https://apogeewatcher.com/images/hero-800.avif&quot; type=&quot;image/avif&quot;&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Use this when the hero URL is stable and not swapped by heavy client-side logic. If the URL only appears after JavaScript runs, preload may fire too late—fix &lt;strong&gt;when&lt;/strong&gt; the URL is known, not only &lt;strong&gt;how&lt;/strong&gt; it is loaded.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt;&lt;/strong&gt; on the LCP &lt;code&gt;&lt;img src=&quot;src&quot; alt=&quot;image&quot;&gt;&lt;/code&gt; nudges the browser to fetch that image sooner relative to other images. Use it sparingly (setting high on more than one or two images is usually not helpful) and pair it with &lt;strong&gt;not&lt;/strong&gt; marking that same image as lazy.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Lazy loading&lt;/strong&gt; belongs on below-the-fold images. For anything in the first screen, &lt;strong&gt;omit &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt;&lt;/strong&gt; or you risk delaying the very resource that defines LCP.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Decoding&lt;/strong&gt;: &lt;code&gt;decoding=&quot;async&quot;&lt;/code&gt; can help keep the main thread responsive; test on low-end hardware if you are borderline on LCP.&lt;/p&gt;&lt;h2&gt;CSS background images and LCP&lt;/h2&gt;&lt;p&gt;Background images set in CSS are &lt;strong&gt;not&lt;/strong&gt; &lt;code&gt;&lt;img src=&quot;src&quot; alt=&quot;image&quot;&gt;&lt;/code&gt; elements. They are still eligible for LCP, but the browser can’t reliably discover the underlying image URL until after CSS is parsed—so you can end up with extra LCP resource load delay. You also lose straightforward &lt;code&gt;alt&lt;/code&gt; semantics for critical content.&lt;/p&gt;&lt;p&gt;If your hero is purely decorative, a background can be fine—but you still pay the same byte and timing costs. If the hero carries meaning (product, banner text is not enough), prefer &lt;strong&gt;semantic &lt;code&gt;&lt;img src=&quot;src&quot; alt=&quot;image&quot;&gt;&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;&lt;picture&gt;&lt;/picture&gt;&lt;/code&gt;&lt;/strong&gt; so preload and priority hints map cleanly to the resource.&lt;/p&gt;&lt;p&gt;When you must keep a background, preload it explicitly (e.g. &lt;code&gt;link rel=&quot;preload&quot;&lt;/code&gt; with &lt;code&gt;fetchpriority=&quot;high&quot;&lt;/code&gt; or a matching &lt;code&gt;Link&lt;/code&gt; header) so it starts fetching early, and make sure the CSS/JS that reveals it doesn’t block rendering.&lt;/p&gt;&lt;h2&gt;Third-party CDNs and transforms&lt;/h2&gt;&lt;p&gt;Image CDNs that resize, reformat, and cache at the edge can shrink time-to-bytes dramatically. When you adopt one:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Lock URL parameters&lt;/strong&gt; (width, quality, format) so marketing edits in the CMS do not silently generate new uncached variants.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Watch cache hit ratios&lt;/strong&gt; after deploys; a “small” config change can bust effective caching.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Align transforms&lt;/strong&gt; with your &lt;code&gt;srcset&lt;/code&gt; strategy—duplicating the same logical image under twenty unbounded parameter combinations is a recipe for cache fragmentation.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;CMS uploads and the “full size” trap&lt;/h2&gt;&lt;p&gt;Many CMS/theme setups default new uploads to &lt;strong&gt;full resolution&lt;/strong&gt; and then display them small. The HTML still references a massive file unless your theme registers proper image sizes and the markup uses them.&lt;/p&gt;&lt;p&gt;If you inherit a WordPress or similar build, check: &lt;strong&gt;(1)&lt;/strong&gt; registered image sizes for hero slots, &lt;strong&gt;(2)&lt;/strong&gt; whether the template uses &lt;code&gt;wp_get_attachment_image&lt;/code&gt; with a named size or blindly outputs the original, &lt;strong&gt;(3)&lt;/strong&gt; whether page builders inject full URLs into inline styles. One corrected template often beats dozens of hand-compressed assets nobody uses.&lt;/p&gt;&lt;h2&gt;Verify in the lab, then confirm in the field&lt;/h2&gt;&lt;p&gt;After changes:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Run &lt;strong&gt;PageSpeed Insights&lt;/strong&gt; (or Lighthouse) on &lt;strong&gt;mobile&lt;/strong&gt; and note LCP and the &lt;strong&gt;LCP element&lt;/strong&gt; breakdown (TTFB, resource load delay, duration, render delay).&lt;/li&gt;&lt;li&gt;Compare &lt;strong&gt;field data&lt;/strong&gt; (CrUX) where available—lab wins do not always match real users on slow networks.&lt;/li&gt;&lt;li&gt;If you use &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/how-to-set-up-automated-pagespeed-monitoring-for-multiple-sites&quot;&gt;automated monitoring&lt;/a&gt;, add or check &lt;strong&gt;budgets&lt;/strong&gt; for LCP on key templates so regressions surface when someone ships a new hero asset.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;For a before/after story, &lt;strong&gt;WebPageTest&lt;/strong&gt; filmstrips or Lighthouse’s &lt;strong&gt;View Trace&lt;/strong&gt; help show whether you shortened &lt;strong&gt;resource load duration&lt;/strong&gt; or merely shifted work. If TTFB or render delay still dominates, image tweaks alone will not get you to green.&lt;/p&gt;&lt;p&gt;Document &lt;strong&gt;one&lt;/strong&gt; baseline number (median LCP or Lighthouse LCP) per template so the next redesign has a reference point.&lt;/p&gt;&lt;h2&gt;Tie optimisation to budgets and ownership&lt;/h2&gt;&lt;p&gt;Image work is easy to undo: a new campaign drops a 4 MB PNG into the hero and nobody notices until Search Console complains. Add a &lt;strong&gt;simple budget&lt;/strong&gt; per template: maximum dimensions, maximum encoded kilobytes, and allowed formats. Our &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/performance-budget-thresholds-template&quot;&gt;Performance Budget Thresholds Template&lt;/a&gt; is a starting point if you do not have internal standards yet.&lt;/p&gt;&lt;p&gt;Assign &lt;strong&gt;who approves&lt;/strong&gt; hero assets in the CMS—often a designer uploads once and the performance contract is forgotten. A short checklist in the handover doc beats a post-launch fire drill.&lt;/p&gt;&lt;h2&gt;What to do next&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;Identify the LCP element on your top templates.&lt;/li&gt;&lt;li&gt;Resize and re-encode; wire &lt;code&gt;srcset&lt;/code&gt;/&lt;code&gt;sizes&lt;/code&gt; correctly.&lt;/li&gt;&lt;li&gt;Remove lazy loading from above-the-fold heroes; add preload or &lt;code&gt;fetchpriority&lt;/code&gt; where appropriate.&lt;/li&gt;&lt;li&gt;Re-test in the lab and watch field metrics after release.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Small, measurable steps beat a sweeping “image audit” that never ships.&lt;/p&gt;&lt;h2&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Is the hero image always the LCP element?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;No. LCP is the &lt;strong&gt;largest&lt;/strong&gt; visible element in the viewport; it can be a headline block, a video poster, or another image. Always confirm in your tooling before optimising the wrong asset.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;WebP or AVIF first?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Prefer &lt;strong&gt;AVIF&lt;/strong&gt; with a &lt;strong&gt;WebP&lt;/strong&gt; or &lt;strong&gt;JPEG&lt;/strong&gt; fallback for broad support, or use CDN negotiation if you have verified behaviour across browsers you care about.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Does lazy loading hurt LCP?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Lazy-loading your actual LCP element can delay LCP. In practice, omit &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; for the first-screen hero (and for any image the diagnostics report as LCP).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Do I need a CDN to pass LCP?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Not always, but a CDN often cuts latency and improves repeat visits. If TTFB or download time dominates your LCP breakdown, origin geography and caching deserve attention alongside image bytes.&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/14052/image-optimisation-strategies-for-better-lcp-scores</guid>
<pubDate>Sat, 25 Apr 2026 06:55:16 +0000</pubDate>
</item>
<item>
<title>Mobile vs Desktop Core Web Vitals: Why You Need to Monitor Both</title>
<link>https://coderlegion.com/14056/mobile-vs-desktop-core-web-vitals-why-you-need-to-monitor-both</link>
<description>&lt;p&gt;Most teams treat Core Web Vitals like one scoreboard. They run a quick test, pick a single set of scores, and move on. The problem is that Core Web Vitals are defined per &lt;strong&gt;page load&lt;/strong&gt;; &lt;strong&gt;device&lt;/strong&gt; shows up in &lt;em&gt;how&lt;/em&gt; you measure—mobile versus desktop in lab emulation, or in field data grouped by form factor. The same URL can therefore produce different LCP, INP, and CLS results across those contexts. Mobile and desktop travel different routes through your UI, assets, network conditions, and interaction patterns. If you monitor only one side, you will miss regressions that matter—and you will struggle to justify prioritisation when clients ask, “Why did this change?”&lt;/p&gt;&lt;h2&gt;The trap: one device, one story&lt;/h2&gt;&lt;p&gt;It’s easy to fall into a workflow like this:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Mobile is “important”, so you track mobile CWV only.&lt;/li&gt;&lt;li&gt;Desktop is “nice to have”, so you leave it until later.&lt;/li&gt;&lt;li&gt;When something breaks, you re-run tests and pick the latest scores to explain the incident.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This approach has two predictable failure modes:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Hidden regressions&lt;/strong&gt; — A fix that improves desktop experience can still leave mobile failing (or vice versa).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Unclear communication&lt;/strong&gt; — You end up explaining different symptoms with one set of numbers. Clients rightly lose confidence.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;If you want monitoring that supports real delivery and client-ready reporting, you need a repeatable &lt;em&gt;paired&lt;/em&gt; view: &lt;strong&gt;mobile + desktop&lt;/strong&gt; for the same pages, the same cadence, and the same triage rules.&lt;/p&gt;&lt;p&gt;If you need a quick primer on the metrics themselves, start with &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/what-are-core-web-vitals-a-practical-guide-for-2026&quot;&gt;What Are Core Web Vitals?&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Why mobile vs desktop Core Web Vitals diverge&lt;/h2&gt;&lt;p&gt;Core Web Vitals can look “similar” at a headline level, but the underlying causes often differ. The most common reasons:&lt;/p&gt;&lt;h3&gt;Different rendering and loading conditions&lt;/h3&gt;&lt;p&gt;Mobile is constrained: less CPU headroom, different caching patterns, and more aggressive resource variation. That shows up strongly in:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;LCP&lt;/strong&gt; (Largest Contentful Paint): often driven by large images, fonts, or other heavy elements on the critical path (the LCP element can also be a text block or a video poster, depending on the page). If those pieces behave differently across breakpoints, LCP will diverge.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Different interaction patterns (INP)&lt;/h3&gt;&lt;p&gt;INP captures interaction responsiveness, which often behaves differently by device due to:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Touch vs pointer interactions&lt;/li&gt;&lt;li&gt;Different event targets and UI density&lt;/li&gt;&lt;li&gt;Varying execution cost on lower-end hardware&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you only look at one device’s INP, you can miss “works on desktop” but “feels slow on phones” issues.&lt;/p&gt;&lt;h3&gt;Different layout stability (CLS)&lt;/h3&gt;&lt;p&gt;CLS is highly sensitive to responsive layout, late-loading elements, and dynamic components that appear only under certain breakpoints (ads, banners, late injected UI, etc.). A page can be stable on desktop and still shift on mobile.&lt;/p&gt;&lt;p&gt;For a deeper explanation of what each metric actually means, see &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/lcp-inp-cls-what-each-core-web-vital-means-and-how-to-fix-it&quot;&gt;LCP, INP, CLS: What Each Core Web Vital Means and How to Fix It&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;What to monitor in practice (beyond the total score)&lt;/h2&gt;&lt;p&gt;Monitoring both devices is necessary, but it’s not sufficient by itself.&lt;/p&gt;&lt;p&gt;You also need to monitor &lt;em&gt;the right dimensions&lt;/em&gt;:&lt;/p&gt;&lt;h3&gt;1. Treat each device as its own budget&lt;/h3&gt;&lt;p&gt;Instead of one “CWV target” for the page, define device-specific thresholds for the metrics you care about. A pass on desktop should not automatically compensate for a fail on mobile.&lt;/p&gt;&lt;p&gt;This keeps decisions defensible when you propose fixes to stakeholders.&lt;/p&gt;&lt;p&gt;If you want a structured way to set thresholds, use our &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/performance-budget-thresholds-template&quot;&gt;Performance Budget Thresholds Template&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;2. Compare by change, not by absolute numbers alone&lt;/h3&gt;&lt;p&gt;Absolute CWV numbers can vary slightly run-to-run. What should drive action is:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;What changed since the last known good period&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Which metric moved first&lt;/strong&gt; (LCP vs INP vs CLS)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Which device changed&lt;/strong&gt; (mobile-first incidents vs desktop-only issues)&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;3. Triage using “worst metric per device”&lt;/h3&gt;&lt;p&gt;A practical triage rule:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;For mobile: focus on the single worst metric (LCP/INP/CLS) and the reason it is failing.&lt;/li&gt;&lt;li&gt;For desktop: do the same.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Then decide whether you have a shared root cause (both devices fail similarly) or breakpoint/device-specific problems.&lt;/p&gt;&lt;h2&gt;A practical monitoring workflow for agencies&lt;/h2&gt;&lt;p&gt;If you want this to work across clients and pages, keep it repeatable. Here’s a workflow you can run every week:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Choose pages that reflect real funnel risk&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;Homepage (first impression)&lt;/li&gt;&lt;li&gt;Key category or service pages (high intent)&lt;/li&gt;&lt;li&gt;Conversion pages (where UX pain becomes business cost)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Run paired analysis for the same pages&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;Mobile + desktop tests on the same cadence&lt;/li&gt;&lt;li&gt;Stable analysis conditions (avoid mixing “random checks” with planned ones)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Record findings in the same order&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;Mobile: LCP → INP → CLS (and a quick “what it likely affects” note)&lt;/li&gt;&lt;li&gt;Desktop: LCP → INP → CLS&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Assign device-specific priority&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;If mobile fails and desktop passes, your “first fix” should usually start mobile unless you have a desktop-only user segment.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Set alerts that match the story&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;Budget breaches on a device should trigger the device’s reporting, not just the overall page score.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Deliver client-ready reporting&lt;/strong&gt;&lt;ul&gt;&lt;li&gt;Give clients a paired narrative: “what you saw” and “what you changed next”.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;For the setup side of automated monitoring across multiple sites, see &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/how-to-set-up-automated-pagespeed-monitoring-for-multiple-sites&quot;&gt;How to Set Up Automated PageSpeed Monitoring for Multiple Sites&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;And if you’re turning this into deliverables, the &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/blog/client-ready-core-web-vitals-report-outline&quot;&gt;Client-Ready Core Web Vitals Report Outline&lt;/a&gt; helps you package the evidence into something stakeholders actually read.&lt;/p&gt;&lt;h2&gt;Interpreting results: three common scenarios&lt;/h2&gt;&lt;p&gt;When you review mobile vs desktop CWV together, you’ll usually fall into one of these buckets:&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Scenario&lt;/th&gt;&lt;th&gt;What it often means&lt;/th&gt;&lt;th&gt;How you should respond&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Mobile failing, desktop ok&lt;/td&gt;&lt;td&gt;Mobile critical path or interactive cost is the bottleneck&lt;/td&gt;&lt;td&gt;Prioritise mobile-first fixes (hero/LCP and interaction latency)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Desktop failing, mobile ok&lt;/td&gt;&lt;td&gt;Desktop-only layout or heavy JS path&lt;/td&gt;&lt;td&gt;Focus on desktop breakpoints, scripts, and layout stability&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Both failing consistently&lt;/td&gt;&lt;td&gt;Shared design debt or performance regressions&lt;/td&gt;&lt;td&gt;Treat it as a system-level problem, then verify with paired reruns&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;The important part is that you avoid the “one score explains everything” habit. Paired monitoring turns CWV from a vanity chart into a decision system.&lt;/p&gt;&lt;h2&gt;What your client update should say (example wording)&lt;/h2&gt;&lt;p&gt;When clients ask “why are there two scores?”, they usually want a single paragraph that explains what changed and what you will do next.&lt;/p&gt;&lt;p&gt;Here’s a simple template you can reuse:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Mobile-first incident (mobile fails, desktop ok):&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;“Mobile performance is out of budget right now (LCP/INP/CLS), while desktop is within budget. This pattern usually points to a mobile-specific bottleneck: hero rendering timing, touch interaction cost, or a late-loading component that behaves differently on smaller breakpoints.”&lt;/li&gt;&lt;li&gt;“Next step: we’ll apply a targeted first-fix on the affected mobile path, then re-run the same paired checks to confirm both the device budget and the user-story are improving.”&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Shared incident (both devices failing in a similar way):&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;“Both mobile and desktop are currently out of budget for the same metric area. That usually means a shared component, shared asset, or shared build/deploy change rather than a single device quirk.”&lt;/li&gt;&lt;li&gt;“Next step: we’ll verify what changed in the release window, then test the fix with paired checks to ensure the improvement holds across devices.”&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you include field data (for example, when you do CrUX-aware reporting), keep the wording consistent: explain what your lab checks caught, and how the field view supports the same story. The goal is less debate and more action.&lt;/p&gt;&lt;h2&gt;A quick consistency check for every report&lt;/h2&gt;&lt;p&gt;Before you send your update, run this quick self-check:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Are you using the same page set for both devices (so the comparison is fair)?&lt;/li&gt;&lt;li&gt;Did you name the &lt;em&gt;first&lt;/em&gt; metric to fail on each device (so the triage is clear)?&lt;/li&gt;&lt;li&gt;Does your next step match the device that is failing (or explain why you’re fixing something shared first)?&lt;/li&gt;&lt;li&gt;Did you state how you will verify after changes (re-run paired checks, not “we’ll look later”)?&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Client-ready reporting: avoid confusion with one sentence&lt;/h2&gt;&lt;p&gt;Clients often ask why you’re reporting two device scores.&lt;/p&gt;&lt;p&gt;Your answer should be simple:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;“Mobile and desktop measure different experiences. We monitor both so we catch issues that only appear on one device and so our fixes stay prioritised and verifiable.”&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;When you present this in a consistent report format, it is easier for stakeholders to focus on the next actions instead of arguing over a single headline score.&lt;/p&gt;&lt;h2&gt;Operational checklist for your next report&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Pick the same set of pages every reporting cycle&lt;/li&gt;&lt;li&gt;Confirm mobile + desktop are both included in the schedule&lt;/li&gt;&lt;li&gt;Use device-specific thresholds for LCP/INP/CLS&lt;/li&gt;&lt;li&gt;Triage by worst metric per device, then explain likely root cause&lt;/li&gt;&lt;li&gt;Reference a repeatable next step (fix + verify, not just “we will look into it”)&lt;/li&gt;&lt;li&gt;Share a paired narrative that stakeholders can understand in under two minutes&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;FAQ&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Do I need to monitor both mobile and desktop if mobile gets most traffic?&lt;/strong&gt;&lt;br&gt;Yes. Even if mobile dominates, desktop still represents business risk for a portion of your audience. More importantly, fixes can improve one device while leaving the other failing. Paired monitoring prevents blind spots.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Which metric should I start with: LCP, INP, or CLS?&lt;/strong&gt;&lt;br&gt;Start with the worst metric on each device (mobile and desktop separately). In many audits, improving LCP is the fastest high-impact win, while INP usually surfaces interaction pain and CLS highlights layout instability—but the right first lever depends on what is actually failing.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How often should we review paired CWV?&lt;/strong&gt;&lt;br&gt;For most agency workflows, weekly review is a good starting point. For active releases or client campaigns, you may need tighter cadence to verify that fixes actually hold.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;What if a page behaves differently by device (e.g. different layout/components)?&lt;/strong&gt;&lt;br&gt;That’s exactly why paired monitoring helps. Explain the difference in your report: the breakpoint experience is part of the user journey, and device-specific findings lead to device-specific fixes.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Will paired monitoring slow down the workflow?&lt;/strong&gt;&lt;br&gt;It shouldn’t. The operational cost should live in automation, not manual re-checks. If your monitoring is scheduled and your reporting is templated, you get more reliable evidence without extra churn.&lt;/p&gt;&lt;hr&gt;&lt;p&gt;If you want a repeatable way to &lt;a target=&quot;_blank&quot; rel=&quot;nofollow&quot; href=&quot;https://apogeewatcher.com/&quot;&gt;monitor mobile and desktop Core Web Vitals&lt;/a&gt; across client portfolios (with paired evidence, budgets, and client-ready reporting), Apogee Watcher is built for that workflow.&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/14056/mobile-vs-desktop-core-web-vitals-why-you-need-to-monitor-both</guid>
<pubDate>Mon, 13 Apr 2026 23:52:33 +0000</pubDate>
</item>
</channel>
</rss>