Images in 2026: AVIF, WebP and srcset
Most pages ship more image data than they need and still manage to cause layout shift. Four decisions fix both: which format, which sizes, how the browser is told about them, and when each file loads. This guide is the decision order, with the markup for each.
Choose a format by what the image is
| Content | Best default | Why |
|---|---|---|
| Photographs | AVIF, with WebP and JPEG fallback | Lossy compression tuned for continuous tone |
| Screenshots, UI, flat illustration | PNG, or lossless WebP | Sharp edges survive; MDN prefers PNG when precise reproduction matters |
| Logos, icons, simple line art | SVG | Resolution independent, tiny, styleable |
| Animated loops | A video file, if motion is needed at all | Far smaller than an animated GIF in web.dev's example |
| Transparency over photographic content | AVIF or WebP with alpha | JPEG has no alpha channel |
Some honest points about the codecs, all from MDN's file type guide:
- JPEG works everywhere and is the universal fallback. Re-encoding a lossy file adds loss again, so always export from the original source.
- WebP offers much better compression than PNG or JPEG, with transparency and animation.
- AVIF generally compresses better than WebP, but its support is newer, so MDN recommends a fallback. It also lacks progressive rendering, so the file must finish downloading before it displays, which MDN says has little real-world effect when the files are much smaller.
- web.dev reports that almost all browsers support AVIF today, and MDN lists Chrome, Edge, Opera, Safari and Firefox. Check MDN's browser compatibility table when you decide, rather than trusting a summary from last year. A
<picture>fallback chain makes support a non-issue either way.
Do not chase a single quality number such as "80". The right setting depends on the image. Export two or three, view them at the size they will be shown, and choose the smallest one you cannot tell from the source.
Serve several sizes with srcset and sizes
A 2400-pixel-wide photograph shown in a 400-pixel card wastes most of its bytes. srcset lists the available files with their real pixel widths; sizes tells the browser how wide the slot will be. This first example uses JPEG, which every browser can decode, because a plain srcset has no way to say "skip this format":
<img
src="/img/harbour-800.jpg"
srcset="/img/harbour-400.jpg 400w,
/img/harbour-800.jpg 800w,
/img/harbour-1600.jpg 1600w"
sizes="(min-width: 960px) 33vw, 100vw"
width="1600" height="1000"
alt="Fictional example: a small boat at a quiet harbour at dusk">
Read the sizes value as a rule list: at a viewport 960 pixels or wider the image occupies a third of the width, otherwise all of it. The browser divides each w descriptor by that slot width to get an effective pixel density, then chooses a candidate. MDN's wording is that the browser uses the descriptors with sizes to pick one, so treat the choice as the browser's, not a guarantee. A few rules from MDN keep it valid:
- Use
wdescriptors, and make each number match the file's real width. Do not mixwandxdescriptors in onesrcset. Usexonly when the image has a fixed CSS size. sizesis only meaningful withwdescriptors. Percentages are not allowed in it, so usevwor fixed lengths.- Without
sizes, the default is100vw, the full viewport width. A small card then picks a file meant for a hero. - Keep the same aspect ratio in every candidate, so one pair of
widthandheightattributes is true for all of them.
Which widths to export
Work backwards from the largest slot. With the sizes rule above, a 1440 CSS pixel viewport gives a slot of about 475 pixels (33 percent of 1440). A screen with a pixel density of 1 needs 475 pixels, a density of 2 needs 950 and a density of 3 needs about 1425. Against the three files listed, a browser would likely take the 800-pixel file at density 1 and the 1600-pixel file at density 2, which is almost double the 950 pixels needed. A 1000-pixel candidate would fit that case better. The arithmetic tells you to add a width only where a common slot falls between two files by a wide margin, not to generate dozens. For a full-width hero that can be 1600 CSS pixels wide, exporting 800, 1200, 1600 and 2400 pixels covers nearly every screen. If your build or hosting service creates variants on demand, give it the widths; if you export by hand, keep the list short enough that you will actually regenerate it when the image changes.
Wrap formats in picture
When you want AVIF with a fallback, the <picture> element lets the browser take the first <source> whose type it understands.
<picture>
<source type="image/avif" srcset="/img/harbour-800.avif 800w, /img/harbour-1600.avif 1600w" sizes="(min-width: 960px) 33vw, 100vw">
<source type="image/webp" srcset="/img/harbour-800.webp 800w, /img/harbour-1600.webp 1600w" sizes="(min-width: 960px) 33vw, 100vw">
<img src="/img/harbour-800.jpg" width="1600" height="1000" alt="Fictional example: a small boat at a quiet harbour at dusk">
</picture>
The <img> inside is not optional. It carries the alt text, the dimensions and the fallback file, and it is the element all the loading attributes apply to. Google's image documentation asks for an img with a src as the fallback whenever you use picture, and says it finds images through that src, including one inside picture.
Art direction
<picture> has a second use: swapping crops. A wide crop that works on desktop may need a tighter portrait crop on a phone so the subject stays readable. Use media on the <source> for that. Give each source its own width and height, because the crops have different ratios, and a mismatch between the ratio the browser reserves and the file it loads makes the page jump. web.dev's guide to avoiding layout shift says major browsers now support these attributes on <source>.
<picture>
<source media="(max-width: 600px)" type="image/avif" srcset="/img/hero-portrait-800.avif" width="800" height="1000">
<source media="(max-width: 600px)" srcset="/img/hero-portrait-800.jpg" width="800" height="1000">
<img src="/img/hero-wide-1600.jpg" width="1600" height="900" alt="">
</picture>
The empty alt marks a decorative image. Keep format selection and art direction as separate concerns where you can: each added crop multiplies the files you must export.
Reserve the space
Always put width and height attributes on the <img>. web.dev explains that browsers compute an aspect ratio from them before the file arrives, so the box exists at the right height and nothing jumps when the image appears. Pair them with max-width: 100%; height: auto; in CSS so the image still scales. This is the most common single cause of avoidable layout shift, and it is a two-attribute fix.
Tell the browser when to load
Three attributes control timing:
| Attribute | Use it on | Effect |
|---|---|---|
loading="lazy" | Images below the first screen | Defers the request until the image is near the viewport |
fetchpriority="high" | The one or two images likely to be the largest on first view | Raises the starting priority among early requests |
decoding="async" | Large images that are not critical | The next paint does not wait for the image to decode |
web.dev explains why fetchpriority helps: Chrome starts images at low priority and raise it once layout shows them in the viewport, so a hint in the markup lets the hero start high. The same page warns that setting it on more than one or two images defeats the purpose.
The mistake to avoid is lazy-loading the largest image on the first screen. That delays the exact element Largest Contentful Paint is waiting for, as described in Core Web Vitals in plain language. Three further details from MDN matter for loading="lazy":
- Width and height are especially important on lazy images. An unloaded image has a size of zero, so without dimensions the content below it moves when it appears.
- Deferral only happens when JavaScript is enabled, an anti-tracking measure.
- Lazy images do not hold up the window
loadevent, even if they sit inside the viewport.
Mistakes that keep showing up
- A
sizesvalue left at the default. Without it the browser assumes the image fills the viewport, so a small card downloads a file meant for a hero. - Exporting only the large version.
srcsetwith a single entry is just an<img>with extra syntax. - Resizing in CSS only. Scaling a 3000-pixel file down with
width: 300pxstill downloads all 3000 pixels. - Background images for content. CSS backgrounds cannot carry alt text, cannot be lazy-loaded by attribute, and Google says it does not index CSS images.
- Stripping every dimension for "responsive" layouts. Keep the attributes and let CSS scale them; the ratio is what prevents the jump.
- AVIF in a bare
srcset. With notypeon a<source>, a browser that cannot decode the format has no way to skip it.
Two kinds of image on one page
A fictional article page has a 1600 by 1000 hero photograph and six 4:3 thumbnails.
- Hero: export AVIF and WebP at 800 and 1600 widths and a JPEG fallback. Write the
<picture>withsizes="100vw". Addwidth="1600" height="1000",fetchpriority="high", and noloadingattribute. - Thumbnails: export 400 and 800 widths. Write
sizes="(min-width: 960px) 33vw, 50vw". Addwidth="800" height="600"andloading="lazy". - Check the Network panel with the cache disabled: each image should request one file, and the thumbnail files should be the smaller variants on a narrow viewport.
- Resize the window and reload. A different size should be selected at a different width. If the same file is always chosen, the
sizesvalue is wrong.
When a video is the wrong answer
A muted looping video beats an animated GIF by a wide margin, so swapping a GIF for video is usually right. web.dev's guide shows one case: a 3.7 MB GIF became a 551 KB MP4 and a 341 KB WebM, and it recommends <video autoplay loop muted playsinline> to reproduce a GIF's behaviour. That is one example, not a rate, so measure your own. The harder question is whether the motion should exist at all.
- The motion is decoration. If removing it changes no meaning, a still image plus a little CSS is cheaper and calmer.
- It is the first thing the page loads. A video hero adds a poster, a large file and a decoder to the critical path. For LCP, web.dev counts the poster image or the first frame, whichever is earlier, so optimise the poster as an image.
- Autoplay motion over five seconds. WCAG 2.2.2 (Level A) asks for a way to pause, stop or hide movement that starts automatically, lasts more than five seconds and sits alongside other content, unless it is essential. If you cannot offer that, use a still. See prefers-reduced-motion, done properly.
- The content is information. Text inside a video or an image cannot be indexed or read by assistive technology. Put it in HTML.
Alt text and search
Alt text describes the image's purpose in context; leave it empty (alt="") for purely decorative images so screen readers skip them. Google's image guidance asks for descriptive filenames and alt text, and says it finds images through the src of an <img>, even when the element is inside <picture>, while it does not index CSS images. Its guidance on lazy loading adds that Search does not scroll or click, so images should load when they come into the viewport, which built-in loading="lazy" does. If an image matters to search, it belongs in the HTML.
Checklist
- Use AVIF or WebP for photographs with a JPEG fallback, SVG for simple graphics.
- Provide
srcsetwith real widths and asizesvalue that matches the layout. - Add
widthandheightto every<img>, and to<source>when crops differ. - Lazy-load below the fold; give the one or two key first-screen images
fetchpriority="high". - Keep video for motion that carries meaning, and give it a pause control.
Questions and answers
Should I use AVIF or WebP?
Both load in current major browsers. MDN says AVIF generally compresses better than WebP but does not support progressive rendering, and that AVIF needs a fallback in WebP, JPEG or PNG through a picture element. Judge the output by eye, not by a fixed quality number.
What is the sizes attribute for?
It tells the browser how wide the image will be displayed, before layout is known, so it can choose a file from srcset. MDN says that without it the browser assumes 100vw, the full viewport width.
Should every image be lazy-loaded?
No. Lazy-load images below the first screen. The image likely to be the largest element on first view should load eagerly, and web.dev suggests fetchpriority high for it.
Does Google index AVIF and WebP images?
Google's image documentation lists WebP and AVIF among the formats Google Search supports, alongside BMP, GIF, JPEG, PNG and SVG, for images referenced in the src of an img element.
Sources
- Responsive images (MDN) developer.mozilla.org
- The img element (MDN) developer.mozilla.org
- Image file type and format guide (MDN) developer.mozilla.org
- Optimize resource loading with Fetch Priority (web.dev) web.dev
- Image SEO best practices (Google Search Central) developers.google.com