Serve the right image to the right screen with srcset and sizes, reserve picture for art direction, and master lazy loading.
Open this lesson in KodokonImages typically account for half of a page's weight: they are your first performance lever. The core mechanism is srcset with w descriptors, which declares the actual widths of the available files, paired with sizes, which announces the intended display width. Key point: the browser picks the image via its preload scanner, before it has even computed the CSS layout. Without sizes, it assumes 100vw and often downloads far more than needed. The final choice also factors in screen density: a 2x screen over a 400 px area will fetch a file of roughly 800 px.
<img src="harbor-800.jpg"
srcset="harbor-400.jpg 400w,
harbor-800.jpg 800w,
harbor-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="Old harbor at sunset"
width="800" height="533">With srcset/sizes, the browser stays in charge: it may serve a lighter variant depending on density or data-saving preferences. <picture> flips the logic: you impose the source via <source media> or <source type>. Reserve it for two cases: art direction (a different crop on mobile, not just a size) and format negotiation (AVIF or WebP with a JPEG fallback). For a simple resize, picture is needless complexity.
<picture>
<source media="(max-width: 600px)"
srcset="hero-square.jpg">
<source type="image/avif"
srcset="hero-wide.avif">
<img src="hero-wide.jpg" alt="Museum facade"
width="1200" height="600">
</picture>For everything else on the page, loading="lazy" defers the download until the image approaches the viewport, natively and without JavaScript. Pair it with decoding="async" so decoding does not block rendering, and above all with width and height: the browser derives the aspect ratio and reserves the space, which eliminates layout shifts (CLS). For the critical image, do the opposite of lazy: fetchpriority="high".
<img src="gallery-01.jpg"
alt="Exhibition hall"
loading="lazy" decoding="async"
width="800" height="600">