Documentation Index Fetch the complete documentation index at: https://buttercms.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Responsive images ensure your website delivers optimally-sized images to every device, reducing page load times and bandwidth usage. The ButterCMS Image API makes this easy through URL-based transformations.
Why responsive images matter
Performance : Smaller images load faster on mobile devices
Bandwidth : Save data for users on limited connections
SEO : Google rewards fast-loading pages
User Experience : Images display correctly across all screen sizes
Basic implementation
Using srcset
The srcset attribute lets browsers choose the best image size:
< img
src = "https://cdn.buttercms.com/resize=width:800/abc123"
srcset = "
https://cdn.buttercms.com/resize=width:400/abc123 400w,
https://cdn.buttercms.com/resize=width:800/abc123 800w,
https://cdn.buttercms.com/resize=width:1200/abc123 1200w,
https://cdn.buttercms.com/resize=width:1600/abc123 1600w
"
sizes = "(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
alt = "Responsive image example"
/>
Understanding srcset and sizes
Attribute Purpose srcFallback for browsers that don’t support srcset srcsetList of available image URLs with width descriptors sizesMedia conditions mapping viewport widths to image widths
Common patterns
Full-width hero image
< img
src = "https://cdn.buttercms.com/resize=width:1200/abc123"
srcset = "
https://cdn.buttercms.com/resize=width:640/abc123 640w,
https://cdn.buttercms.com/resize=width:960/abc123 960w,
https://cdn.buttercms.com/resize=width:1280/abc123 1280w,
https://cdn.buttercms.com/resize=width:1920/abc123 1920w
"
sizes = "100vw"
alt = "Hero image"
/>
Blog Post featured image
< img
src = "https://cdn.buttercms.com/resize=width:800/abc123"
srcset = "
https://cdn.buttercms.com/resize=width:400/abc123 400w,
https://cdn.buttercms.com/resize=width:600/abc123 600w,
https://cdn.buttercms.com/resize=width:800/abc123 800w,
https://cdn.buttercms.com/resize=width:1200/abc123 1200w
"
sizes = "(max-width: 768px) 100vw, 800px"
alt = "Blog featured image"
/>
Card grid image
< img
src = "https://cdn.buttercms.com/resize=width:400,height:300,fit:crop/abc123"
srcset = "
https://cdn.buttercms.com/resize=width:200,height:150,fit:crop/abc123 200w,
https://cdn.buttercms.com/resize=width:400,height:300,fit:crop/abc123 400w,
https://cdn.buttercms.com/resize=width:600,height:450,fit:crop/abc123 600w
"
sizes = "(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 400px"
alt = "Card image"
/>
Using the picture element
For art direction (different crops for different devices):
< picture >
<!-- Mobile: square crop -->
< source
media = "(max-width: 600px)"
srcset = "https://cdn.buttercms.com/resize=width:600,height:600,fit:crop/abc123"
/>
<!-- Tablet: 16:9 crop -->
< source
media = "(max-width: 1200px)"
srcset = "https://cdn.buttercms.com/resize=width:1200,height:675,fit:crop/abc123"
/>
<!-- Desktop: wide crop -->
< img
src = "https://cdn.buttercms.com/resize=width:1920,height:800,fit:crop/abc123"
alt = "Art directed image"
/>
</ picture >
Framework examples
React component
function ResponsiveImage ({ src , alt , sizes = '100vw' }) {
const fileId = src . split ( '/' ). pop ();
const baseUrl = 'https://cdn.buttercms.com' ;
const widths = [ 400 , 800 , 1200 , 1600 ];
const srcSet = widths
. map ( w => ` ${ baseUrl } /resize=width: ${ w } / ${ fileId } ${ w } w` )
. join ( ', ' );
return (
< img
src = { ` ${ baseUrl } /resize=width:800/ ${ fileId } ` }
srcSet = { srcSet }
sizes = { sizes }
alt = { alt }
loading = "lazy"
/>
);
}
// Usage
< ResponsiveImage
src = "https://cdn.buttercms.com/abc123"
alt = "My image"
sizes = "(max-width: 768px) 100vw, 800px"
/>
Vue component
< template >
< img
: src = " defaultSrc "
: srcset = " srcSet "
: sizes = " sizes "
: alt = " alt "
loading = "lazy"
/>
</ template >
< script setup >
import { computed } from 'vue' ;
const props = defineProps ({
src: String ,
alt: String ,
sizes: { type: String , default: '100vw' },
widths: { type: Array , default : () => [ 400 , 800 , 1200 , 1600 ] }
});
const fileId = computed (() => props . src . split ( '/' ). pop ());
const baseUrl = 'https://cdn.buttercms.com' ;
const defaultSrc = computed (() =>
` ${ baseUrl } /resize=width:800/ ${ fileId . value } `
);
const srcSet = computed (() =>
props . widths
. map ( w => ` ${ baseUrl } /resize=width: ${ w } / ${ fileId . value } ${ w } w` )
. join ( ', ' )
);
</ script >
Next.js with next/image
import Image from 'next/image' ;
// Custom loader for ButterCMS
const butterLoader = ({ src , width , quality }) => {
const fileId = src . split ( '/' ). pop ();
const q = quality || 75 ;
return `https://cdn.buttercms.com/resize=width: ${ width } /quality=value: ${ q } / ${ fileId } ` ;
};
export default function ButterImage ({ src , alt , ... props }) {
return (
< Image
loader = { butterLoader }
src = { src }
alt = { alt }
{ ... props }
/>
);
}
// Usage
< ButterImage
src = "https://cdn.buttercms.com/abc123"
alt = "My image"
width = { 800 }
height = { 600 }
sizes = "(max-width: 768px) 100vw, 800px"
/>
WebP with fallback
Serve WebP to supported browsers with JPEG fallback:
< picture >
< source
type = "image/webp"
srcset = "
https://cdn.buttercms.com/resize=width:400/output=format:webp/abc123 400w,
https://cdn.buttercms.com/resize=width:800/output=format:webp/abc123 800w,
https://cdn.buttercms.com/resize=width:1200/output=format:webp/abc123 1200w
"
sizes = "(max-width: 768px) 100vw, 800px"
/>
< img
src = "https://cdn.buttercms.com/resize=width:800/abc123"
srcset = "
https://cdn.buttercms.com/resize=width:400/abc123 400w,
https://cdn.buttercms.com/resize=width:800/abc123 800w,
https://cdn.buttercms.com/resize=width:1200/abc123 1200w
"
sizes = "(max-width: 768px) 100vw, 800px"
alt = "WebP with fallback"
/>
</ picture >
Helper functions
JavaScript utility
class ButterImage {
constructor ( url ) {
this . fileId = url . split ( '/' ). pop ();
this . baseUrl = 'https://cdn.buttercms.com' ;
}
resize ( width , height , fit = 'clip' ) {
let params = `width: ${ width } ` ;
if ( height ) params += `,height: ${ height } ` ;
if ( fit !== 'clip' ) params += `,fit: ${ fit } ` ;
return ` ${ this . baseUrl } /resize= ${ params } / ${ this . fileId } ` ;
}
generateSrcSet ( widths , options = {}) {
const { height , fit , format } = options ;
return widths . map ( width => {
let transforms = [];
// Resize
let resizeParams = `width: ${ width } ` ;
if ( height ) {
const scaledHeight = Math . round ( height * ( width / widths [ widths . length - 1 ]));
resizeParams += `,height: ${ scaledHeight } ` ;
}
if ( fit ) resizeParams += `,fit: ${ fit } ` ;
transforms . push ( `resize= ${ resizeParams } ` );
// Format conversion
if ( format ) {
transforms . push ( `output=format: ${ format } ` );
}
const url = ` ${ this . baseUrl } / ${ transforms . join ( '/' ) } / ${ this . fileId } ` ;
return ` ${ url } ${ width } w` ;
}). join ( ', ' );
}
}
// Usage
const img = new ButterImage ( 'https://cdn.buttercms.com/abc123' );
console . log ( img . resize ( 800 ));
// https://cdn.buttercms.com/resize=width:800/abc123
console . log ( img . generateSrcSet ([ 400 , 800 , 1200 ], { format: 'webp' }));
// https://cdn.buttercms.com/resize=width:400/output=format:webp/abc123 400w, ...
Best practices
Use Appropriate Sizes Don’t serve 4K images for thumbnails. Match image sizes to display sizes.
Lazy Loading Add loading="lazy" for images below the fold.
WebP When Possible WebP offers 25-35% smaller files than JPEG at similar quality.
Test Performance Use Lighthouse or WebPageTest to verify image optimization.
Recommended breakpoints
Device Type Typical Width Suggested srcset widths Mobile 320-480px 400w, 600w Tablet 768-1024px 800w, 1000w Desktop 1200-1920px 1200w, 1600w, 1920w Large Display 2560px+ 2400w
Next steps
Image Transformations All transformation options
Security Secure your images
Performance CDN optimization
Media Field Working with media fields