Lazy-load images, components, and data that are below the initial viewport fold. Loading everything upfront makes the user wait for content they haven't scrolled to yet — increasing Time to Interactive and burning mobile data on content the user may never see.
Loading all images, components, and data upfront forces users to wait for content they have not scrolled to yet. This directly increases Largest Contentful Paint (LCP) and Time to Interactive (TTI). On mobile networks, it wastes bandwidth on content the user may never see — studies show 50%+ of below-fold content is never viewed.
BeforeMerge scans your pull requests against this rule and 3+ others. Get actionable feedback before code ships.
The initial viewport (above the fold) is the only content the user sees when the page first loads. Everything below the fold is invisible until the user scrolls. Loading below-fold content upfront has three costs:
Slower initial load: The browser must download, parse, and render below-fold images and components before the above-fold content becomes interactive. This directly increases LCP and TTI.
Wasted bandwidth: On mobile networks (which account for 60%+ of web traffic), downloading images the user may never scroll to wastes data and slows down everything else on the page.
Main thread blocking: Loading and rendering below-fold components occupies the main thread, delaying interaction handlers for above-fold content. Users experience jank and unresponsive buttons.
Lazy loading defers below-fold work until the user scrolls near it, making the initial load fast and efficient.
Lazy-load all images, heavy components, and non-critical data that are below the initial viewport. Use loading="lazy" for images, React.lazy() for components, and intersection observers for data fetching.
// All images load immediately — even ones 3000px below the fold
export function ProductPage({ products }: { products: Product[] }) {
return (
<div>
<HeroSection /> {/* Above fold */}
{products.map(product => (
<div key={product.id}>
<img src={product.image} /> {/* Loads immediately even if below fold */}
<HeavyReviewsWidget productId={product.id} /> {/* Loads immediately */}
</div>
))}
</div>
);
}import { lazy, Suspense } from "react";
const HeavyReviewsWidget = lazy(() => import("./reviews-widget"));
export function ProductPage({ products }: { products: Product[] }) {
return (
<div>
<HeroSection /> {/* Above fold — loads immediately */}
{products.map(product => (
<div key={product.id}>
<img
src={product.image}
loading="lazy" {/* Deferred until near viewport */}
width={400}
height={300}
/>
<Suspense fallback={<ReviewsSkeleton />}>
<HeavyReviewsWidget productId={product.id} />
</Suspense>
</div>
))}
</div>
);
}Search for images without lazy loading:
grep -rn '<img' --include="*.tsx" --include="*.jsx" | grep -v 'loading='Use Lighthouse to identify "offscreen images" that should be lazy-loaded.
loading="lazy" to all <img> elements below the fold (do NOT lazy-load above-fold hero images — this hurts LCP)React.lazy() with Suspense for heavy below-fold componentsImage component which handles lazy loading automaticallywidth and height attributes to prevent layout shift during lazy load