Images: AVIF, HEIC, or JPG?

I’m at a loss!

I should have tested this earlier, but I’ve just realised HEIC format is not supported by Google. I’ve been happily going along serving up all my images in HEIC format, not realising that was Apple’s bespoke format.

For my images I’m more interested in size than quality, so should I use AVIF or JPG, rather than HEIC?

I would say it depends on how many browsers you need to support. Avif does everything jpeg does but better. If you expect these photos will only ever be viewed on browsers supporting avif I’d definitely say use avif

You could serve more than one/all <picture>: The Picture element - HTML: HyperText Markup Language | MDN

Thanks for your replies.

I am at a loss as how to you provide for every eventuality. From what I gather you can use:

<figure>
   <picture>
      <source ...>
      <source ...>
      <source ...>
      <img..>
   </picture>

   <figcaption>...</figcaption>
</figure>

But I’m unsure as to how to include an image.jpg, image.avif, image.heic, and an image.webp. I think I’ll go with .avif and hope for the best.

  • <source srcset=…> for additional types
  • <img src=…> for main/jpeg

Thanks, @charlie137.

What I’m struggling with is how to get the separate images and their extensions – .avif, .jpg, .webp – included in my shortcode:

<figure>
    <picture>
    <a href="{{ path }}">
        <source srcset="{{ path }}" type="image/avif" />
        <img src="{{ path }}" type="image/jpg" class="responsive" {%- if caption %} alt="{{ caption }}"{%- endif %} />
    </a>
        {%- if caption -%}
            <figcaption>{{ caption }}</figcaption>
        {%- endif -%}
    </picture>
</figure>

Any pointers?

Try to drop picture tag completely and add srcset into the img to use anchors:

<img src=“$MAIN” srcset=“$TYPE1, $TYPE2” width=“…” height=“…” />

You mean more like this:

<figure>
    <a href="{{ path | jpg }}">
        <img src="{{ path | jpg }}" srcset="{{ path | avif, path | webp }}" class="responsive" {%- if caption %} alt="{{ caption }}"{%- endif %} />
    </a>
        {%- if caption -%}
            <figcaption>{{ caption }}</figcaption>
        {%- endif -%}
</figure>

My strategy (not invented by me - found on the internet years ago) is to pretend serving JPEG & PNG only, but to actually serve WEBP and AVIF if the browser’s HTTP Accept header indicates interest.

In the NGINX http section, suffixes get generated :

http {
    # ...

    map $http_accept $avif_suffix {
        default ".no-avif"; # try_files fails for non-existent file.jpg.no-avif
        "~*avif" ".avif";
    }

    map $http_accept $webp_suffix {
        default ".no-webp"; # try_files fails for non-existent file.jpg.no-webp
        "~*webp" ".webp";
    }

    # ...
    
    server {
        # ...

        location /choose/your/path {
            location ~ \.(png|jpe?g)$ {
                add_header Vary "Accept-Encoding";
                log_not_found off;
                expires max;
                try_files $uri$avif_suffix $uri$webp_suffix $uri =404;
            }
        }
    }
}

The HTML then only contains JPG and PNG images. The markup is already complex enough with the srcset and sizes:

<img src="foo-512.jpg"
     srcset="
	    foo-128.jpg 128w,
		foo-256.jpg 256w,
		foo-384.jpg 384w,
		foo-512.jpg 512w
	 "
	 sizes="
	    (min-width: 1280px) 6rem,
		                    5rem"
	 width="512"
	 height="512"
	 alt="..."
	 title="..."
>

The browser might request foo-512.jpg. Depending on its Accept HTTP header, it will generate a suffix .avif or .no-avif as well as .webp or .no-webp.

In the location block, try_files will serve foo-512.jpg.avif first, if found, otherwise try foo-512.jpg.webp, and only then fall back go foo.jpg.

If AVIF is not supported by the browser as indicated by its Accept header, then try_files will look for foo-512.jpg.no-avif, which won’t exist, and go on to trying foo-512.jpg.webp and succeed (or foo-512.jpg.no-webp and fail, to then serve the actual JPG).

I’ve got a systemd scheduled task generating *.jpg.avif and *.jpg.webp from all *.jpg files, and the same for *.png.