Skip to main content
    Homepage speed optimization guide
    Field-Tested on This Site

    Homepage Speed Optimization Guide

    The practical techniques that make a homepage load fast on real phones — each one explained, and each one applied on this very site.

    9 techniques, ordered roughly by impact for a typical content homepage.

    1. Compress and modernize images

    Images are usually the heaviest bytes on a homepage and the most common LCP element. Every kilobyte you remove directly shortens load time on phones.

    • Serve AVIF first, WebP as fallback, JPEG last — AVIF is typically 30–50% smaller than JPEG at the same quality.
    • Generate responsive sizes (e.g. 640w, 1024w, 1440w) and use srcset so phones never download desktop-sized files.
    • Target quality 45–60 for photos; visitors can't tell the difference, but the file size drops dramatically.
    • Never upscale: the largest generated size should match the largest rendered size.

    On this site: This site serves every hero and content image as AVIF/WebP srcset with a compressed JPEG fallback.

    2. Preload the hero image

    The hero image is usually the LCP element. Browsers discover it late — after parsing HTML and CSS — unless you tell them about it up front.

    • Add a <link rel="preload" as="image"> in the document head for the hero image only.
    • Include imagesrcset and imagesizes on the preload so the browser fetches the exact responsive variant the <img> will use — a mismatch means a wasted double download.
    • Set fetchpriority="high" on the hero <img> itself.
    • Never preload more than one or two resources; preloading everything defeats the purpose.

    On this site: Our build emits a single responsive AVIF preload that exactly matches the homepage hero's srcset and sizes.

    3. Lazy-load below-the-fold images

    Images the visitor can't see yet shouldn't compete for bandwidth with the ones they can. Lazy loading keeps the network focused on what matters first.

    • Add loading="lazy" and decoding="async" to every image below the fold.
    • Never lazy-load the hero or any above-the-fold image — that delays LCP instead of helping it.
    • Always set explicit width and height (or aspect-ratio) so lazy images don't cause layout shifts when they arrive.

    On this site: All below-the-fold imagery on this site lazy-loads; the hero is the one deliberate exception.

    4. Split your JavaScript by route

    Shipping one giant bundle makes every visitor download and parse code for pages they may never open. Parsing JavaScript is especially expensive on mid-range phones.

    • Lazy-load every route except the homepage with dynamic import() so each page's code loads on demand.
    • Keep the homepage bundle lean — it contains your LCP element and sets the first impression.
    • Audit the bundle for heavy libraries; a charting or animation library imported on one page shouldn't weigh down all of them.

    On this site: Every page here except the homepage is a lazy-loaded route, and we use pure CSS animations instead of JavaScript animation libraries.

    5. Trim web fonts

    Each font weight is a separate download, and fonts can block text rendering. Font files frequently account for 100KB+ of avoidable transfer.

    • Audit which weights you actually use and delete the rest — most sites need 3–4, not 8.
    • Use font-display: swap so text renders immediately in a system font while the web font loads.
    • Preconnect to the font host (or self-host) to skip the connection setup delay.

    On this site: We trimmed an unused light weight from our body font and preconnect to the font host in the document head.

    6. Prevent layout shifts

    Content jumping while the page loads frustrates visitors and hurts your CLS score. Shifts also delay the moment the page feels stable and usable.

    • Reserve space for every image, embed, and ad with explicit dimensions or aspect-ratio.
    • Avoid injecting banners or notices above existing content after load.
    • If a component waits on an image before revealing (like a parallax hero), make sure the placeholder occupies the same space.

    On this site: Our hero waits for its image before animating in, and every image carries fixed dimensions — our measured CLS is 0.0001.

    7. Cache static assets aggressively

    Returning visitors shouldn't re-download your logo, fonts, or stylesheets. Good caching makes repeat visits feel instant.

    • Serve hashed, immutable assets (JS, CSS, images) with Cache-Control: max-age=31536000, immutable.
    • Keep HTML uncached or short-cached so new deploys reach visitors immediately.
    • Use a CDN so assets are served from a location physically close to the visitor.

    On this site: Our build hashes every asset filename, so they can be cached for a year and update instantly when the hash changes.

    8. Cut unused JavaScript and CSS

    Dead code still gets downloaded, parsed, and compiled. Lighthouse routinely finds 50–100KB of unused JavaScript on typical homepages.

    • Run Lighthouse's 'Reduce unused JavaScript' audit and trace each flagged chunk to its import.
    • Prefer tree-shakeable imports (named imports from ES modules) over whole-library imports.
    • Remove dependencies you no longer use — each one is transfer and parse time on every visit.

    On this site: We removed our animation library entirely in favor of CSS, and track unused-JS findings in every Lighthouse run.

    9. Measure with real-user monitoring

    Lab tests (Lighthouse) tell you what a simulated phone experiences. Real-user monitoring tells you what your actual visitors experience — which is what search engines use for ranking.

    • Collect LCP, CLS, INP, FCP, and TTFB from real visits with the web-vitals library.
    • Attribute LCP to its element (hero image vs heading vs something else) so you know what to fix.
    • Break results down by device type — a fast desktop score can hide a slow phone experience.
    • Track p75, not averages: one fast visit shouldn't hide nine slow ones.

    On this site: This site reports anonymized Web Vitals from every visit, split by device and hero vs non-hero LCP, viewable in our admin dashboards.