Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the native loading='lazy' attribute on images that are below the initial viewport or otherwise noncritical. Keep the likely Largest Contentful Paint (LCP) image and other immediately visible content eager, and give every image explicit intrinsic width and height values (or an equivalent aspect-ratio reservation). The browser decides when a lazy image is close enough to fetch, so there is no universal pixel threshold to configure.

How to lazy-load an image

Add loading='lazy' directly to the img element:

<img
  src='gallery-image.jpg'
  alt='A red kite flying over the beach'
  width='1200'
  height='800'
  loading='lazy'>

The loading attribute is an enumerated HTML attribute. Its lazy state lets the user agent defer fetching until its own conditions are met. eager requests immediate loading, and missing or invalid values use the eager behavior. Because the user agent controls the distance at which a lazy image starts loading, do not document or tune your code around a fixed number of pixels.

A complete page example

<!doctype html>
<html lang='en'>
<head>
  <meta charset='utf-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
  <title>Lazy-loaded gallery</title>
  <style>
    .gallery img {
      display: block;
      width: 100%;
      height: auto;
    }
  </style>
</head>
<body>
  <main>
    <h1>Coastal gallery</h1>

    <!-- Visible at the start: leave this eager. -->
    <img
      src='hero-coast.jpg'
      alt='Cliffs above the Atlantic at sunrise'
      width='1600'
      height='900'
      fetchpriority='high'>

    <section class='gallery' aria-label='More coastal photos'>
      <img
        src='tide-pool.jpg'
        alt='A tide pool reflecting the evening sky'
        width='1200'
        height='800'
        loading='lazy'>
      <img
        src='lighthouse.jpg'
        alt='A white lighthouse on a rocky point'
        width='1200'
        height='800'
        loading='lazy'>
      <img
        src='dunes.jpg'
        alt='Grass-covered dunes beside the beach'
        width='1200'
        height='800'
        loading='lazy'>
    </section>
  </main>
</body>
</html>

The CSS can scale an image to the available width while the intrinsic dimensions preserve its aspect ratio. Use the image’s real dimensions, not arbitrary numbers.

Which images should be lazy and which should be eager?

Decide based on whether the image is needed immediately, not on a blanket rule for every img element.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Image situation Loading choice Why
Hero, banner, product photo or other image visible at the start Eager (omit loading or use loading='eager') It may be the LCP image or part of the first useful view. Deferring it can delay content people expect immediately.
Images below the fold in an article or gallery loading='lazy' The browser can avoid fetching bytes that a visitor never reaches and reduce competition for network and CPU resources.
Images near the fold whose importance changes with layout Choose case by case Responsive reflow and browser heuristics determine when the image becomes relevant; test the resulting experience.
Decorative or nonessential imagery Usually lazy when offscreen There is little reason to spend initial bandwidth on content that is neither immediately visible nor meaningful.

This is a trade-off, not a guaranteed percentage improvement. Deferral helps when an image is never viewed or would otherwise compete with critical work, but delaying an image that is expected immediately can worsen perceived or measured loading.

Reserve layout space to prevent shifts

Set both width and height on practical img elements. The browser can calculate the aspect ratio before downloading the file and reserve space, so surrounding text does not jump when the image arrives. This is particularly important for lazy images: without a known size, an unloaded image may occupy little or no space and then push content down later.

<img
  src='map.jpg'
  alt='Walking map of the historic district'
  width='1000'
  height='667'
  loading="eager"
  style='max-width:100%;height:auto'>

If intrinsic dimensions cannot be placed on the element, reserve an equivalent aspect ratio with CSS. The reservation must represent the actual file’s proportions; inventing dimensions creates a different problem when the image renders.

Responsive images and the picture element

Keep loading='lazy' on the img element, including when it is inside picture. The fallback img is the element that carries the loading behavior and its dimensions:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<picture>
  <source media='(min-width: 900px)' srcset='mountain-large.webp'>
  <source media='(min-width: 500px)' srcset='mountain-medium.webp'>
  <img
    src='mountain-small.webp'
    alt='Snow-covered mountain above a valley'
    width='1200'
    height='800'
    loading='lazy'>
</picture>

Make the dimensions describe the selected image’s common aspect ratio. If your sources have different proportions, reserve the ratio used by each rendered variant with an appropriate responsive CSS strategy.

Accessibility is separate from loading

Lazy loading never replaces alternative text. Give a meaningful image useful alt text that communicates its purpose when it cannot be seen or fetched. For a purely decorative image, use an empty value, alt='', so assistive technology can skip it. A delayed request does not change what the image means or whether it needs an accessible name.

Use fetchpriority and decoding carefully

fetchpriority is a separate, relative-priority hint. fetchpriority='high' can reinforce that a genuinely critical image matters more, while low can lower its relative priority. It does not switch lazy behavior to eager behavior, and it should be applied sparingly; too many high-priority hints undermine the browser’s scheduling decisions. It may complement a preload for a truly critical image, but do not preload every image.

The decoding attribute expresses a decoding preference such as async, sync or auto. It is independent of whether fetching is deferred, so changing decoding is not a substitute for choosing loading='lazy' or eager loading.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What the browser does at runtime

There is no fixed lazy threshold

The user agent decides when a lazy resource is close enough to load. Network conditions, layout, viewport size and the browser’s own scheduling all affect the decision. Code should express importance and dimensions, not assume a universal distance.

The load event may fire first

A page’s window.load event does not guarantee that every lazy image has finished. If an application depends on one particular image, observe that image itself:

const image = document.querySelector('#report-chart');

function imageReady() {
  console.log('The report chart finished loading or was already complete.');
}

if (image.complete) {
  imageReady();
} else {
  image.addEventListener('load', imageReady, { once: true });
}

Attach the listener before the image is expected to enter the loading range, and handle an image that is already complete when your script runs.

Disabled scripting changes behavior

When scripting is disabled, browsers do not perform native lazy loading in order to avoid creating a scroll-position tracking vector. In that situation, images load eagerly. Treat lazy loading as a browser hint, not as a security boundary or a guarantee that a request will never occur.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Performance: what to measure

Look at the image’s role and the visitor’s path rather than expecting a universal score improvement.

  • Confirm the LCP candidate is discovered promptly and is not accidentally lazy.
  • Check that below-the-fold images are not competing with critical HTML, CSS and fonts during the first view.
  • Verify that every delayed image reserves its space; otherwise reduced initial bytes can be offset by layout movement.
  • Test narrow and wide viewports because an image that is below the fold on one layout may be visible immediately on another.
  • Test a cold load and a cached load. Cache hits can make a change appear faster without changing the first visit.
  • Test on a slower connection and with scripting disabled so you understand the fallback behavior.

Native lazy loading is intentionally heuristic. A result that is faster for one page, viewport or network can be neutral or worse for another.

Troubleshooting common problems

Symptom Likely cause Fix
The image request starts immediately The image is near the initial viewport, the browser decided it was close enough, or scripting is disabled. Check whether immediate loading is appropriate. Do not fight the browser with arbitrary thresholds.
The hero appears late The hero or LCP candidate was marked lazy. Remove loading='lazy' or set eager behavior. Use a selective priority hint only when the image is genuinely critical.
Text jumps when an image appears No intrinsic dimensions or aspect-ratio reservation. Add the real width and height, or reserve the correct CSS aspect ratio.
Code runs before a gallery image is ready The page load event fired before the lazy request completed. Listen for that image’s load event and account for its complete state.
Assistive technology gets no useful description Missing, generic or incorrectly empty alt text. Describe meaningful images; use empty alt only for decoration.
Adding lazy loading shows no benefit All images are viewed, images are already cached, or the page is constrained elsewhere. Measure initial bytes, image discovery and layout stability on realistic viewport and network conditions.

A practical implementation checklist

  1. List the images visible before scrolling and identify the likely LCP image.
  2. Leave those critical images eager; mark genuinely offscreen images with loading='lazy'.
  3. Add accurate intrinsic width and height values to every image.
  4. Write meaningful alt text, or alt='' for decoration.
  5. Keep lazy loading on the img inside any picture element.
  6. Use fetchpriority only for a small number of clearly important images.
  7. For scripts that depend on an image, observe that image instead of relying on window.load.
  8. Test multiple viewport sizes, slow connections, cached loads and scripting-disabled behavior.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

When you need repeatable screenshots to check whether lazy images, layout reservations and responsive states render correctly, ScreenshotNeo can capture a URL without maintaining your own browser automation. Its full-page capture loads lazy images. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off.

Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and each response identifies the result with X-Page-Verdict and X-Billed headers. An MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

One GET request is enough (see the ScreenshotNeo API documentation):

curl -G 'https://api.screenshotneo.com/v1/shot' -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
open('shot.webp', 'wb').write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account to capture your page.

Frequently Asked Questions

Can a lazy image be guaranteed to load before a particular scroll position?

No. The HTML standard leaves the loading distance to the user agent, so your code can express importance but cannot set one universal threshold.

Does an empty alt value mean an image should be lazy?

No. alt='' describes a decorative image for accessibility; loading priority is a separate decision based on when the image is needed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why can a page look complete while a gallery image is still missing?

A lazy image may not have loaded when window.load fires. Observe the specific image’s complete state or load event when your application needs it.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.