Responsive Image Optimization with srcset
Learn how to combine srcset, sizes, and picture to serve sharp responsive images without downloading unnecessarily large files.
srcset lets a browser choose among image files; sizes tells it how wide the image is expected to render at different layouts. For layout-dependent image widths, pair width candidates such as 480w and 800w with an accurate sizes value. Use density candidates such as 1x and 2x when the rendered size is fixed. Use <picture> when the browser may need a different crop or image format.
The examples below use illustrative dimensions. Set candidate widths, sizes, and intrinsic dimensions to match your actual files and CSS.
1. How srcset and sizes work
srcset lists image candidates and describes either their intrinsic pixel widths or their pixel densities. With width descriptors, sizes supplies a slot-width hint: a comma-separated list of media-condition and length pairs. The browser uses the first matching condition, then considers the hint and display pixel density when choosing a candidate. It retains discretion over the final choice, so markup describes available resources and layout intent rather than forcing one exact file. See the MDN responsive images guide and web.dev’s image guidance.
<img
src="/images/photo-800.jpg"
srcset="/images/photo-480.jpg 480w, /images/photo-800.jpg 800w, /images/photo-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw, 50vw"
width="1200"
height="800"
alt="A hiker looking over a mountain valley"
>
Here, the slot is expected to fill the viewport up to 600 CSS pixels wide and use half the viewport width above that breakpoint. Those values are correct only if the page’s CSS produces those slot widths. The src is a fallback/default reference, and the width and height represent the source image’s intrinsic dimensions and ratio.
Width descriptors
Use width descriptors for files with different intrinsic widths when the displayed slot changes with the layout. The descriptor is a pixel width, not a CSS width. For example, photo-800.jpg 800w says that this candidate is 800 pixels wide. Pair this descriptor model with sizes.
Density descriptors
For a fixed rendered size with variants made for different pixel densities, use density descriptors and omit sizes:
<img
src="/images/avatar-1x.jpg"
srcset="/images/avatar-1x.jpg 1x, /images/avatar-2x.jpg 2x"
width="96"
height="96"
alt="A person smiling"
>
Do not mix the width-descriptor and density-descriptor models in the same candidate list. A responsive card or article image whose CSS width varies normally calls for width candidates plus sizes; a fixed-size icon or avatar with density variants can use 1x and 2x.
2. Write sizes to match the layout
The sizes attribute describes the expected rendered slot width before the browser downloads the image. It does not set the element’s CSS width. CSS still controls the rendered size, for example:
.article-image {
display: block;
width: 100%;
height: auto;
}
Suppose an image fills a single-column layout below 700px, occupies half the viewport from 700px through 1199px, and is capped at 600px on larger screens. A corresponding hint could be:
<img
src="/images/story-800.jpg"
srcset="/images/story-480.jpg 480w, /images/story-800.jpg 800w, /images/story-1200.jpg 1200w"
sizes="(max-width: 700px) 100vw, (max-width: 1199px) 50vw, 600px"
width="1200"
height="800"
alt="A ceramic bowl on a workbench"
>
The first matching media condition supplies the slot hint. Keep the order from narrower/specific conditions to the default. This example assumes the CSS has the same breakpoints and produces those widths. If the page has a fixed-width content column, gutters, or a sidebar, write lengths that reflect the actual image slot instead of using a rough viewport fraction.
A practical way to derive sizes
- Inspect the image’s CSS layout at each responsive breakpoint.
- Calculate the image’s rendered slot width, including column widths and gaps.
- Write media-condition/length pairs for those cases, with the default case last.
- Check the result at narrow, breakpoint, and wide viewport sizes and revise if the slot hint differs from the rendered width.
For a two-column layout with a 24px gap and 32px total horizontal page padding, for instance, each column is roughly half of the remaining content width. A simple 50vw hint overstates the slot because it ignores the gap and padding. Use a layout-accurate expression or a conservative approximate length that reflects the page’s CSS. The aim is a useful hint, not false precision.
3. Choose between srcset and picture
| Need | Use | Why |
|---|---|---|
| Same image/crop at several responsive widths | <img srcset sizes> |
The browser chooses a suitable resolution for the slot. |
| Same fixed-size image at different display densities | <img srcset> with 1x/2x |
Density candidates describe variants for a fixed rendered size. |
| Different crops or art direction at breakpoints | <picture> with conditional <source> elements |
The source can change based on an explicit media condition. |
| Prefer a format when supported, with a fallback | <picture> with type-qualified sources |
Sources can offer format alternatives before the fallback image. |
Use <picture> when the source itself should change conditionally. Keep an <img> inside it: that remains the image element and provides the fallback.
<picture>
<source
media="(max-width: 600px)"
srcset="/images/landscape-mobile.jpg"
>
<source
type="image/webp"
srcset="/images/landscape-480.webp 480w, /images/landscape-800.webp 800w"
sizes="(max-width: 900px) 100vw, 900px"
>
<img
src="/images/landscape-800.jpg"
srcset="/images/landscape-480.jpg 480w, /images/landscape-800.jpg 800w"
sizes="(max-width: 900px) 100vw, 900px"
width="1200"
height="800"
alt="A landscape at sunrise"
>
</picture>
In this illustration, a narrow viewport selects the mobile crop. Otherwise the browser can use the WebP source where applicable, while the nested JPEG <img> provides a fallback. Keep the candidates and sizes aligned across sources so each represents the intended crop and slot. For format-only alternatives without a crop change, keep the same visual content in each format.
4. Preserve layout and accessibility
Provide intrinsic width and height attributes when known, using the source image’s actual dimensions. Browsers can use that ratio to reserve space while CSS changes the rendered width, which helps avoid layout shifts as the resource loads. Responsive CSS can scale the image while preserving the ratio:
img {
max-width: 100%;
height: auto;
}
Write useful alt text that conveys the image’s meaning in context. Use an empty alt="" for an image that is purely decorative and adds no information. For informative images, describe relevant content rather than file names or the fact that it is an image.
Check that every candidate URL exists, returns the intended image, and has the dimensions its descriptor claims. A wrong descriptor or a sizes value that diverges from CSS can lead the browser to choose a file that is too large or too small. Do not remove src; it provides a default image reference for the image element and fallback contexts.
5. Build and verify an image set
- Start from the source image and produce a small set of useful widths for the slots your layout uses. Avoid generating many nearly identical files without a delivery need.
- Keep the crop consistent across width candidates unless you are deliberately using art direction.
- Use clear, stable URLs in
srcsetand make each width descriptor match the file’s intrinsic pixel width. - Set
sizesfrom the rendered CSS layout, not from the candidate widths. - Keep the
src, intrinsic dimensions, and alternative text on the<img>. - Inspect the page at representative viewport widths and pixel densities. Use browser developer tools’ network panel to see which resource was requested, then compare it with the displayed slot and source candidates.
- Repeat after layout or breakpoint changes: responsive markup and CSS need to describe the same layout.
There is no universal byte-saving percentage for srcset. Results depend on the actual source files, slot sizes, display density, compression, browser selection, and delivery conditions. Compare the resources your page actually serves rather than assuming one fixed saving.
6. Common problems and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| The browser downloads a larger image than expected | sizes overstates the slot, is missing for width candidates, or no suitable smaller candidate exists. |
Match sizes to CSS and provide a candidate close to the actual slot multiplied by the needed display density. |
| The image looks soft on a high-density display | The candidate set has no sufficiently large resource, or the slot hint understates the rendered width. | Add an appropriately sized candidate and verify the rendered width and sizes. |
| A mobile crop never appears | The <source media> condition does not match the viewport, or the source precedes/follows competing conditions incorrectly. |
Check the media condition against the actual viewport and order conditional sources from the intended specific cases to general alternatives. |
| A format alternative is ignored | The type does not match the resource, the URL fails, or the nested <img> fallback is missing/invalid. |
Verify the response file and MIME type, test the source URL, and keep a valid fallback image. |
| One candidate is missing or broken | The URL is wrong, deployment omitted the asset, or the descriptor does not describe the file’s actual width. | Request each URL directly, fix deployment/path errors, and align the descriptor with intrinsic pixels. |
| Content jumps when an image loads | Intrinsic dimensions are absent or the reserved ratio differs from the image. | Set correct width and height and preserve the ratio with responsive CSS. |
| Changes appear not to take effect | A cached page or image may be displayed, or a different candidate is still the correct browser choice. | Inspect the actual requested URL in developer tools, reload after deployment, and verify the candidate set and slot hint before changing markup. |
7. Performance, reliability, and cost notes
srcset and sizes help the browser choose from resources you provide; they do not create resized files, compress images, or guarantee a particular transfer size. Your image pipeline must produce the candidate files and keep them available at the referenced URLs. A mismatch between generated assets, descriptors, and layout is a reliability issue as well as a performance issue.
More candidates can give the browser finer choices, but each adds an asset to generate and maintain. Choose widths around real layout slots and densities, then check the network requests on the page. The cost of image delivery depends on your hosting or image service and actual traffic; the research basis for this guide does not establish universal savings or pricing.
8. ScreenshotNeo: capture responsive layouts
Once the responsive markup is deployed, comparing screenshots at several viewport sizes can help reveal crop, sizing, or layout differences. ScreenshotNeo is a website screenshot API and MCP server. It accepts a URL and returns a PNG, JPEG, WebP, or PDF. Its viewport and device options can capture layouts at preset devices or custom dimensions. See the ScreenshotNeo API documentation.
For this page, capture the same URL at a narrow mobile width and a wider desktop width, then inspect whether the intended crop and rendered slot match your responsive rules. A screenshot shows the rendered result; it does not replace checking the browser’s selected image request in developer tools.
Or skip the browser setup
One GET request returns a screenshot. This cURL example saves a WebP capture of the example page:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Cookie banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers report the page verdict and billing status. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo’s free plan to capture up to 1,000 screenshots a month with no card.
9. Frequently asked questions
Does srcset guarantee the browser will use the smallest file?
No. It offers candidates and a slot hint; the browser retains discretion when choosing. Provide relevant candidates and an accurate sizes value.
Can sizes replace responsive CSS?
No. CSS controls the rendered layout. sizes describes the expected image slot to guide selection among width candidates.
Should I use picture for every responsive image?
No. For the same content and crop at different widths, use srcset on <img>. Choose <picture> when the source should change conditionally, such as a different crop or format.
Do width descriptors mean CSS pixels?
No. A width descriptor such as 800w describes the candidate file’s intrinsic pixel width. The rendered slot is described separately by sizes.


