Alistair Shepherd - Front-End Developer
SeriesEight
<img
src="/our-image.jpg"
alt="our image"
>
<img
src="/wp-content/uploads/our-image.jpg"
srcset="
/wp-content/uploads/our-image-300x200.jpg 300w,
/wp-content/uploads/our-image-768x512.jpg 768w,
/wp-content/uploads/our-image-1024x683.jpg 1024w,
/wp-content/uploads/our-image-1536x1024.jpg 1536w
"
sizes="(min-width: 800px) 768px, 100vw"
...
>
Size | |
---|---|
Source JPEG | 300kB |
Optimised JPEG | 60kB |
WebP 🙂 | 36kB |
AVIF * 😀 | 28kB |
JPEG XL * 😍 | 24kB |
Size | Chrome | Firefox | Safari | |
---|---|---|---|---|
Source JPEG | 300kB | yes | yes | yes |
Optimised JPEG | 60kB | yes | yes | yes |
WebP 🙂 | 36kB | yes | yes | recent |
AVIF * 😀 | 28kB | yes | recent | no |
JPEG XL * 😍 | 24kB | no | no | no |
Size | |
---|---|
Source JPEG | 300kB |
Optimised JPEG | 60kB |
WebP 🙂 | 36kB |
AVIF * 😀 | 28kB |
JPEG XL * 😍 | 24kB |
<picture>
<source
media="(-webkit-min-device-pixel-ratio: 1.5)"
srcset="https://example.com/images/our-image_width1200_quality40.jpg 1200w"
sizes="...">
<img
srcset="https://example.com/images/our-image_width600_quality80.jpg 600w"
sizes="..."
alt="">
</picture>
iPhone 12 Pro (right) screen:
The browser could decide to load an image with resolution 3x larger than it's displayed - 9x increase in file size!!!
We can mitigate increase in file size by increasing the image compression without visible effect.
<img
loading="lazy"
decoding="async"
>
<picture>
<source
type="image/avif"
media="(-webkit-min-device-pixel-ratio: 1.5)"
srcset="/assets/image/otter-300-q40.avif 300w, /assets/image/otter-450-q40.avif 450w, /assets/image/otter-600-q40.avif 600w,
/assets/image/otter-800-q40.avif 800w, /assets/image/otter-1000-q40.avif 1000w, /assets/image/otter-1200-q40.avif 1200"
sizes="(min-width: 87rem) 40rem, (min-width: 768px) calc(50vw - 4rem), calc(100vw - 2rem)">
<source
type="image/avif"
srcset="/assets/image/otter-300-q80.avif 300w, /assets/image/otter-450-q80.avif 450w, /assets/image/otter-600-q80.avif 600w,
/assets/image/otter-800-q80.avif 800w, /assets/image/otter-1000-q80.avif 1000w, /assets/image/otter-1200-q80.avif 1200"
sizes="(min-width: 87rem) 40rem, (min-width: 768px) calc(50vw - 4rem), calc(100vw - 2rem)">
<source
type="image/webp"
media="(-webkit-min-device-pixel-ratio: 1.5)"
srcset="/assets/image/otter-300-q40.webp 300w, /assets/image/otter-450-q40.webp 450w, /assets/image/otter-600-q40.webp 600w,
/assets/image/otter-800-q40.webp 800w, /assets/image/otter-1000-q40.webp 1000w, /assets/image/otter-1200-q40.webp 1200"
sizes="(min-width: 87rem) 40rem, (min-width: 768px) calc(50vw - 4rem), calc(100vw - 2rem)">
<source
type="image/webp"
srcset="/assets/image/otter-300-q80.webp 300w, /assets/image/otter-450-q80.webp 450w, /assets/image/otter-600-q80.webp 600w,
/assets/image/otter-800-q80.webp 800w, /assets/image/otter-1000-q80.webp 1000w, /assets/image/otter-1200-q80.webp 1200"
sizes="(min-width: 87rem) 40rem, (min-width: 768px) calc(50vw - 4rem), calc(100vw - 2rem)">
<source
media="(-webkit-min-device-pixel-ratio: 1.5)"
srcset="/assets/image/otter-300-q40.jpg 300w, /assets/image/otter-450-q40.jpg 450w, /assets/image/otter-600-q40.jpg 600w,
/assets/image/otter-800-q40.jpg 800w, /assets/image/otter-1000-q40.jpg 1000w, /assets/image/otter-1200-q40.jpg 1200"
sizes="(min-width: 87rem) 40rem, (min-width: 768px) calc(50vw - 4rem), calc(100vw - 2rem)">
<img
alt="otter standing on a log looking out majestically"
src="/assets/image/otter-1200-q80.jpg"
srcset="/assets/image/otter-300-q80.jpg 300w, /assets/image/otter-450-q80.jpg 450w,
/assets/image/otter-600-q80.jpg 600w, /assets/image/otter-800-q80.jpg 800w,
/assets/image/otter-1000-q80.jpg 1000w, /assets/image/otter-1200-q80.jpg 1200"
sizes="(min-width: 87rem) 40rem, (min-width: 768px) calc(50vw - 4rem), calc(100vw - 2rem)"
width="1200"
height="784"
loading="lazy"
decoding="async"
>
</picture>
Source and image credit:
HTTP Archive Web Almanac, 2021 - Media Chapter
✅
✅
❎
❎
and many more
Web Server
HTML
CSS
JS
Images
Images
User's browser
Optimised
Source
Web Server
User's browser
HTML
CSS
JS
Images
Images
Web Server
Optimised
Source
Web Server
User's browser
HTML
CSS
JS
Images
Images
Media Storage
https://example.imagecdn.com
https://example.imagecdn.com
/https://oursite.com
/src/assets
/example.jpg
https://example.imagecdn.com
/example.jpg
https://example.imagecdn.com
/example.jpg
?w=600&h=400
https://example.imagecdn.com/fetch
/example.jpg
/w_600,h_400
.../w_300,h_600,c_thumb,g_auto/...
Tall banner with automatic gravity
.../w_1000,h_400,c_fill,g_north,
e_colorize:30,co_rgb:dd14d1/...
Wide banner anchored to top, coloured pink
<picture>
<source
media="(-webkit-min-device-pixel-ratio: 1.5)"
srcset="
https://example.imagecdn.com/images/w_300,q_40/otter.jpg 300w,
https://example.imagecdn.com/images/w_450,q_40/otter.jpg 450w,
https://example.imagecdn.com/images/w_600,q_40/otter.jpg 600w,
https://example.imagecdn.com/images/w_800,q_40/otter.jpg 800w,
https://example.imagecdn.com/images/w_1000,q_40/otter.jpg 1000w,
https://example.imagecdn.com/images/w_1200,q_40/otter.jpg 1200w"
sizes="(min-width: 87rem) 40rem, (min-width: 768px) calc(50vw - 4rem), calc(100vw - 2rem)">
<img
alt="otter standing on a log looking out majestically"
src="https://example.imagecdn.com/images/w_800,q_80/otter.jpg"
srcset="
https://example.imagecdn.com/images/w_300,q_80/otter.jpg 300w,
https://example.imagecdn.com/images/w_450,q_80/otter.jpg 450w,
https://example.imagecdn.com/images/w_600,q_80/otter.jpg 600w,
https://example.imagecdn.com/images/w_800,q_80/otter.jpg 800w,
https://example.imagecdn.com/images/w_1000,q_80/otter.jpg 1000w,
https://example.imagecdn.com/images/w_1200,q_80/otter.jpg 1200w"
sizes="(min-width: 87rem) 40rem, (min-width: 768px) calc(50vw - 4rem), calc(100vw - 2rem)"
width="1200"
height="784"
loading="lazy"
decoding="async"
>
</picture>
Cloudinary WordPress plugin
Imagekit.io integrations
<img src="{{ image | img_url: '800x300', crop: 'center' }}" ...>
Shopify Image CDN
{% image {
name: 'otter.jpg'
alt: 'an otter standing on a log looking majestic'
srcset: [300, 450, 600, 800, 1000, 1200]
sizes: '100vw'
width: 1200
height: 800
loading: 'lazy'
class: 'image-class mb-xl'
} %}
accud.io/imagecdn-11ty
import Image from 'components/Image'
export default function () {
return (
<Image
src="otter.jpg"
alt="an otter standing on a log looking majestic"
srcset={[300, 450, 600, 800, 1000, 1200]}
sizes="100vw"
width="1200"
height="800"
loading="lazy"
className="image-class mb-xl"
/>
)
}
accud.io/imagecdn-react
<?php
echo image([
'image' => 'otter.jpg',
'alt' => 'an otter standing on a log looking majestic',
'srcset' => [300, 450, 600, 800, 1000, 1200],
'sizes' => '100vw',
'width' => 1200,
'height' => 800,
'loading' => 'lazy',
'class' => 'image-class'
]);
accud.io/imagecdn-php
For very high performing sites different origin has an impact
Solutions for nginx and Netlify
location /cdn/ {
proxy_pass https://example.imagecdn.com/;
}
[[redirects]]
from = '/cdn/:image'
to = 'https://example.imagecdn.com/:image'
status = 200
These slides, my sources and helpful links on image CDNs available at accud.io/imagecdns
On twitter and most social media @accudio
My website and blog posts alistairshepherd.uk