6.1 KiB
6.1 KiB
Responsive Images Patterns
Complete guide to serving optimal images for different devices and screen sizes.
srcset with Named Variants
Best for consistent, predefined sizes.
<img
srcset="
https://imagedelivery.net/HASH/ID/mobile 480w,
https://imagedelivery.net/HASH/ID/tablet 768w,
https://imagedelivery.net/HASH/ID/desktop 1920w
"
sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1920px"
src="https://imagedelivery.net/HASH/ID/desktop"
alt="Responsive image"
loading="lazy"
/>
Variants to create:
mobile: width=480, fit=scale-downtablet: width=768, fit=scale-downdesktop: width=1920, fit=scale-down
srcset with Flexible Variants
Best for dynamic sizing (public images only).
<img
srcset="
https://imagedelivery.net/HASH/ID/w=480,f=auto 480w,
https://imagedelivery.net/HASH/ID/w=768,f=auto 768w,
https://imagedelivery.net/HASH/ID/w=1920,f=auto 1920w
"
sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1920px"
src="https://imagedelivery.net/HASH/ID/w=1920,f=auto"
alt="Responsive image"
loading="lazy"
/>
Art Direction (Different Crops)
Serve different image crops for mobile vs desktop.
<picture>
<!-- Mobile: Square crop -->
<source
media="(max-width: 767px)"
srcset="https://imagedelivery.net/HASH/ID/mobile-square"
/>
<!-- Desktop: Wide crop -->
<source
media="(min-width: 768px)"
srcset="https://imagedelivery.net/HASH/ID/desktop-wide"
/>
<!-- Fallback -->
<img
src="https://imagedelivery.net/HASH/ID/desktop-wide"
alt="Art directed image"
loading="lazy"
/>
</picture>
Variants to create:
mobile-square: width=480, height=480, fit=coverdesktop-wide: width=1920, height=1080, fit=cover
High-DPI (Retina) Displays
Serve 2x images for high-resolution screens.
<img
srcset="
https://imagedelivery.net/HASH/ID/w=400,dpr=1,f=auto 1x,
https://imagedelivery.net/HASH/ID/w=400,dpr=2,f=auto 2x
"
src="https://imagedelivery.net/HASH/ID/w=400,f=auto"
alt="Retina-ready image"
/>
Blur Placeholder (LQIP)
Load tiny blurred placeholder first, then swap to full image.
<img
id="lqip-image"
src="https://imagedelivery.net/HASH/ID/w=50,q=10,blur=20,f=webp"
data-src="https://imagedelivery.net/HASH/ID/w=1920,f=auto"
alt="Image with LQIP"
style="filter: blur(10px); transition: filter 0.3s;"
/>
<script>
const img = document.getElementById('lqip-image');
const fullSrc = img.getAttribute('data-src');
const fullImg = new Image();
fullImg.src = fullSrc;
fullImg.onload = () => {
img.src = fullSrc;
img.style.filter = 'blur(0)';
};
</script>
Lazy Loading
Defer loading below-the-fold images.
<!-- Native lazy loading (modern browsers) -->
<img src="..." loading="lazy" alt="..." />
<!-- With Intersection Observer (better control) -->
<img
class="lazy"
data-src="https://imagedelivery.net/HASH/ID/w=800,f=auto"
alt="Lazy loaded image"
/>
<script>
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
observer.unobserve(img);
}
});
});
document.querySelectorAll('img.lazy').forEach(img => observer.observe(img));
</script>
URL Transformations (/cdn-cgi/image/)
Transform ANY publicly accessible image (not just Cloudflare Images storage).
<img
srcset="
/cdn-cgi/image/width=480,format=auto/uploads/photo.jpg 480w,
/cdn-cgi/image/width=768,format=auto/uploads/photo.jpg 768w,
/cdn-cgi/image/width=1920,format=auto/uploads/photo.jpg 1920w
"
sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1920px"
src="/cdn-cgi/image/width=1920,format=auto/uploads/photo.jpg"
alt="Transformed origin image"
loading="lazy"
/>
Recommended Breakpoints
const breakpoints = {
mobile: 480, // Small phones
tablet: 768, // Tablets
desktop: 1024, // Laptops
wide: 1920, // Desktops
ultrawide: 2560 // Large displays
};
sizes attribute:
sizes="
(max-width: 480px) 480px,
(max-width: 768px) 768px,
(max-width: 1024px) 1024px,
(max-width: 1920px) 1920px,
2560px
"
Complete Example
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
img { max-width: 100%; height: auto; display: block; }
</style>
</head>
<body>
<!-- Hero image with art direction -->
<picture>
<source
media="(max-width: 767px)"
srcset="https://imagedelivery.net/HASH/ID/w=480,h=480,fit=cover,f=auto"
/>
<source
media="(min-width: 768px)"
srcset="https://imagedelivery.net/HASH/ID/w=1920,h=1080,fit=cover,f=auto"
/>
<img
src="https://imagedelivery.net/HASH/ID/w=1920,h=1080,fit=cover,f=auto"
alt="Hero image"
/>
</picture>
<!-- Responsive gallery images -->
<img
srcset="
https://imagedelivery.net/HASH/ID/w=480,f=auto 480w,
https://imagedelivery.net/HASH/ID/w=768,f=auto 768w,
https://imagedelivery.net/HASH/ID/w=1024,f=auto 1024w
"
sizes="
(max-width: 480px) 100vw,
(max-width: 768px) 50vw,
33vw
"
src="https://imagedelivery.net/HASH/ID/w=1024,f=auto"
alt="Gallery image"
loading="lazy"
/>
</body>
</html>
Best Practices
- Always use format=auto: Optimal WebP/AVIF delivery
- Add loading="lazy": Below-the-fold images
- Match sizes to CSS layout: Use
sizesattribute correctly - Provide descriptive alt text: Accessibility
- Use LQIP for perceived performance: Better UX
- Named variants for private: Signed URLs compatible
- Flexible variants for public: Dynamic sizing
- Limit srcset to 3-5 sizes: Balance performance vs flexibility
Official Documentation
- Responsive Images (MDN): https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images
- Cloudflare Images: https://developers.cloudflare.com/images/