On many pages images make up the heaviest part of the transfer. They are also the most common cause of slow loading of the main content and of sudden layout shifts. The good news is that modern HTML offers native tools to serve the right image to the right device, with no external libraries.
Choosing the format
Each format has an area where it performs best:
| Format | Ideal for | Notes |
|---|---|---|
| JPEG | photographs | universal compatibility, no transparency |
| PNG | graphics with transparency, screenshots | lossless, often heavy for photos |
| WebP | photos and graphics | usually lighter than JPEG and PNG at the same quality |
| AVIF | photos | very efficient compression, slower encoding |
| SVG | logos, icons, vector illustrations | infinitely scalable, it is text and compresses well |
For photographs, WebP and AVIF can reduce weight considerably compared with JPEG. For logos and icons, SVG is almost always the best choice: it stays sharp on any screen and weighs a few kilobytes. If the SVG comes from a graphics program, it is worth stripping unnecessary metadata before publishing it.
Offering several formats with picture
The picture element lets the browser pick the first format it supports:
<picture>
<source srcset="/img/photo.avif" type="image/avif">
<source srcset="/img/photo.webp" type="image/webp">
<img src="/img/photo.jpg" alt="Description of the photo"
width="1200" height="800">
</picture>
The final img is mandatory: it is the element actually displayed, with the alt, width and height attributes, while the source elements only change the source file.
Serving the right size
A common mistake is loading a 3000-pixel-wide image to display it in a 400-pixel box. The browser resizes it, but the user has still downloaded the whole file. The srcset and sizes attributes solve the problem:
<img
src="/img/product-800.jpg"
srcset="/img/product-400.jpg 400w,
/img/product-800.jpg 800w,
/img/product-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="Brass table lamp"
width="800" height="800">
srcsetlists the available versions with their actual width (400wmeans 400 pixels).sizestells the browser how wide the image will be on the page: full width on screens up to 600 pixels, half the window otherwise.
With this information the browser works out which file to download, also taking the screen's pixel density into account. A phone with a high-density screen will choose a larger version than the CSS width alone suggests, and that is correct.
If you omit sizes, the browser assumes the image takes up the full width of the window and tends to download versions that are too large.
Reserving space
Setting width and height on the image is not about fixing its visual size (you handle that with CSS); it lets the browser calculate the aspect ratio before the download. It can then reserve the correct space, and the text below does not jump when the image arrives.
img {
max-width: 100%;
height: auto;
}
This rule, combined with the attributes in the HTML, keeps proportions and makes images fluid. For boxes with fixed proportions you can also use aspect-ratio and object-fit: cover.
Lazy loading: yes, but not everywhere
The native loading="lazy" attribute postpones downloading images until they get close to the visible area:
<img src="/img/gallery-12.webp" loading="lazy"
alt="..." width="600" height="400">
It is perfect for galleries, long lists and images at the bottom of the page. It is harmful, however, for the main image at the top of the page: delaying it worsens perceived loading time. For that image use normal loading and, if it is the most important element, add fetchpriority="high".
decoding="async" can also help, letting the browser decode the image without blocking the rest of the rendering.
Alternative text
Optimising an image also means making it understandable. The alt attribute describes the content for screen reader users and appears when the image fails to load. A few rules:
- describe what the image conveys in context, not every detail;
- do not start with "image of": the screen reader already announces that it is an image;
- for purely decorative images use
alt=""(empty, not missing), so they are ignored; - if the image is a link, the
altmust describe the destination.
Automating the work
Manually preparing three formats in four sizes for every image is not sustainable. There are two typical solutions:
- At build time: many static site generators and build tools have plugins that create the variants automatically and write the markup with
srcset. - Through a transformation service: some CDNs and image services generate the requested size and format on the fly via URL parameters and cache the result.
In both cases, keep the high-quality originals: they will let you regenerate the variants when you change the layout or a better format appears.
In short
- Use SVG for logos and icons, WebP or AVIF for photographs, with JPEG as a fallback.
srcsetandsizeslet the browser download only the size it needs.- Always set
widthandheightto avoid layout shifts. - Apply
loading="lazy"to images far from the top of the page, never to the main one. - Write useful alternative text and automate the generation of variants.