Introduction
A gallery of thumbnails is one of the most common patterns on the web, and also one of
the easiest to get wrong from a performance perspective. By default, the browser starts
fetching every <img> it parses — even images that are hundreds of
pixels below the fold and may never be seen. On a gallery page with dozens of thumbnails
that can mean dozens of unnecessary network requests on initial load.
This example applies the lazy-loading technique from
Tutorial 09: Performance & Loading
to a three-image gallery. Each thumbnail uses loading="lazy" so the browser
defers its fetch until the image approaches the viewport. Each thumbnail also links to
the full-resolution version using a plain <a>, so the larger image is
accessible without any JavaScript.
Live demo
Three thumbnails — a product shot, a portrait, and a landscape — are presented in a
responsive grid. Every thumbnail has loading="lazy",
decoding="async", and explicit width and
height attributes. Click any thumbnail to open its full-resolution JPEG
in the browser.
Key markup
Below is the markup for a single gallery item. The pattern is the same for all three:
an <a> wraps the thumbnail and points to the full-resolution source;
the <img> inside carries the lazy-loading attributes and its declared
intrinsic size.
Why these choices matter
loading="lazy" saves bandwidth up front
When a user arrives at the page, only images near the viewport need to be fetched
immediately. loading="lazy" tells the browser to skip the network request
until the image is within a browser-determined threshold of the viewport (typically a
few hundred pixels). On a gallery page with many images, this can eliminate the majority
of image fetches on initial load, freeing bandwidth for the content the user is
actually looking at.
width and height prevent layout shift
When the browser defers an image fetch it also defers knowing how tall the image will
be. Without width and height attributes, the reserved height
is zero; when the image eventually loads it pushes surrounding content down, causing
a jarring Cumulative Layout Shift (CLS). Providing the intrinsic dimensions lets the
browser calculate the correct aspect ratio and reserve the right amount of space even
before the image arrives.
decoding="async" keeps the main thread free
Decompressing a JPEG or WebP file takes CPU time. By default, the browser may perform
this work synchronously, blocking style calculations and rendering while it finishes.
decoding="async" moves the decode off the main thread so the rest of the
page can continue rendering. For thumbnails — which are non-critical by definition —
this is always appropriate.
Plain links instead of a lightbox
A JavaScript lightbox provides a polished UX, but it adds complexity, a script dependency,
and potential accessibility burden. For a learning context, wrapping the thumbnail in a
plain <a href="full-image.jpg"> is simpler, works without JavaScript,
and illustrates the core concept (thumbnail → full resolution) clearly. Real projects
can layer a lightbox on top of this foundation.