Browser Support
Unfortunately, JPEG XL has no browser support on stable releases of browser versions. Chromium-browsers like Chrome, Edge, and Opera, as well as the Firefox browser, support JXL as part of other experimental features behind a flag. Even if these browsers support JPEG XL on stable browser versions, other browsers like Safari and people with outdated browsers don't support JPEG XL. It takes several years to establish a new image format, and in the meantime, you should look for serving content that all users can view.
The picture element
To support every user, you can use the native picture element in HTML. It allows for progressive support. You mention all the file formats you want to serve, and your visitor's browser will only load the first image it supports. This reduced load on your server and the bandwidth usage of your visitors. The advantages are:
- Does not download more than one image at a time.
- Native support for selecting the most appropriate image.
- 96% browser support and automatic fallback.
- Getting this implemented is easy and straightforward.
Implementation
Currently 96% of browsers support the picture element. Even if your grandma visits your website with her disgusting Internet Explorer 2 via her modem, her browser will revert to the default image format when you specify it. Have a look at the following example and copy it if you want to use it for your website:
1<picture>
2 <source srcSet="image.jxl" type="image/jxl" />
3 <source srcSet="image.avif" type="image/avif" />
4 <source srcSet="image.webp" type="image/webp" />
5 <img
6 width="1280" height="720" decoding="async" loading="lazy"
7 src="image.jpg" alt="hopefully an jxl image" />
8</picture>
PS: We added several attributes to the IMG tag to speed up the loading.
Make sure the first source tag is a JXL image for the browser to display the first media type it can handle. You can edit this code snippet to your needs, depending on if you want to serve AVIF or WebP.
Responsiveness
Creating a great visual experience for Retina and 4K displays and mobile devices, we want to make sure that images aren't pixelated or too large for the device, wasting bandwidth. We can do so by implementing the srcSet attribute.
1<picture>
2 <source
3 sizes="(max-width: 640px) 100vw, 640px"
4 srcSet="/image-1280.jxl 1280w, /image-640.jxl 640w, /image-320.jxl 320w"
5 type="image/jxl" />
6 <source
7 sizes="(max-width: 640px) 100vw, 640px"
8 srcSet="/image-1280.avif 1280w, /image-640.avif 640w, /image-320.avif 320w"
9 type="image/avif" />
10 <source
11 sizes="(max-width: 640px) 100vw, 640px"
12 srcSet="/image-1280.avif 1280w, /image-640.webp 640w, /image-320.webp 320w"
13 type="image/webp" />
14 <source
15 sizes="(max-width: 640px) 100vw, 640px"
16 srcSet="/image-1280.avif 1280w, /image-640.jpg 640w, /image-320.jpg 320w"
17 type="image/jpg" />
18 <img
19 width="1280" height="720" decoding="async" loading="lazy"
20 src="/image.jpg" alt="an avif image" />
21</picture>
Components
Creating JPEG XL images for any viewport of any format can be exhausting, so if you're using a framework, make sure to use a component to save yourself some time. For example, we use the following image component in NextJS:
1export default function Image(props: { alt: string; url: string }) {
2 return (
3 <picture>
4 <source
5 type="image/jxl"
6 srcSet={`/img/${props.url}-1536.jxl 1536w, /img/${props.url}-768.jxl 768w, /img/${props.url}-576.jxl 576w, /img/${props.url}-384.jxl 384w`}
7 sizes="(max-width: 768px) 100vw, 768px"
8 />
9 <source
10 type="image/avif"
11 srcSet={`/img/${props.url}-1536.avif 1536w, /img/${props.url}-768.avif 768w, /img/${props.url}-576.avif 576w, /img/${props.url}-384.avif 384w`}
12 sizes="(max-width: 768px) 100vw, 768px"
13 />
14 <source
15 type="image/webp"
16 srcSet={`/img/${props.url}-1536.webp 1536w, /img/${props.url}-768.webp 768w, /img/${props.url}-576.webp 576w, /img/${props.url}-384.webp 384w`}
17 sizes="(max-width: 768px) 100vw, 768px"
18 />
19 <source
20 type="image/jpeg"
21 srcSet={`/img/${props.url}-1536.jpg 1536w, /img/${props.url}-768.jpg 768w, /img/${props.url}-576.jpg 576w, /img/${props.url}-384.jpg 384w`}
22 sizes="(max-width: 768px) 100vw, 768px"
23 />
24 <img
25 loading="lazy"
26 decoding="async"
27 width={2880}
28 height={1620}
29 src={`/img/${props.url}-1536.jpg`}
30 alt={props.alt}
31 title={props.alt}
32 />
33 </picture>
34 );
35}
This allows us to easily add an image like this:
1<Image src="frog" alt="frog looking nicely" />

Please remember to provide fallback images for older browser versions or experimental use. Otherwise, your user experience may suffer as images are not rendered.