ScreenshotNeo

BlogHow-to

How to Deliver Responsive Images for Different Screen Sizes

Use srcset and sizes to serve appropriately sized images, and picture when layouts need different crops. Learn the markup, layout rules, and common fixes.

By the ScreenshotNeo team4 October 20269 min read

Use srcset with width candidates and sizes when the image content stays the same but its rendered width changes. Use <picture> with media-conditioned sources when a phone or other layout needs a different image or crop. In both cases, keep CSS responsible for the layout, give the browser accurate image-selection hints, and reserve space with image dimensions or an aspect ratio.

The browser uses the available candidates, the expected slot width, and device characteristics to choose an image. You provide the candidates and hints; you do not have to write JavaScript to switch files at breakpoints.

1. Choose the right responsive image pattern

What changes? Use Why
The image content stays the same; its layout width varies. img with width-descriptor srcset and sizes The browser can select a candidate suitable for the expected rendered width.
The rendered width is fixed, but the display pixel density varies. img with density-descriptor srcset, such as 1x and 2x These candidates vary in resolution for a fixed rendered size.
The image, composition, or crop should change with the layout. picture with media-conditioned source elements and an img child This is art direction: select different content or crops for different conditions.
The page should not jump when the image loads. width and height attributes or a reserved CSS aspect ratio The browser can allocate space before image bytes arrive.

Do not use x descriptors for an image whose rendered size depends on viewport width. For that fluid case, use width descriptors and describe the slot with sizes.

2. Serve the same image at different widths

Prepare multiple files with the same visual content at different intrinsic widths. For example, photo-480.jpg should be 480 pixels wide, photo-800.jpg 800 pixels wide, and photo-1200.jpg 1200 pixels wide. Then provide them as candidates:

<img
  src="photo-800.jpg"
  srcset="photo-480.jpg 480w, photo-800.jpg 800w, photo-1200.jpg 1200w"
  sizes="(width <= 600px) 100vw, 800px"
  width="1200"
  height="800"
  alt="A red bicycle leaning against a brick wall"
>

Replace the example alternative text with a concise description of the image’s meaningful content, or use alt="" if it is purely decorative. The src value is a fallback for browsers or situations that do not use the candidate set.

How srcset and sizes work together

  • srcset lists files and their intrinsic widths. The w descriptor is metadata about each candidate file, not its CSS display width.
  • sizes describes the image’s expected rendered slot width under media conditions. In this example, the slot is the full viewport width at widths up to 600 CSS pixels, and 800 CSS pixels above that.
  • The browser combines that slot hint with candidate widths and device characteristics to choose a resource. The browser makes the selection; the markup does not force one exact file for every device.
  • CSS still controls the actual layout size. Keep sizes consistent with the real slot or the browser may choose an unnecessarily large or small candidate.

The sample sizes value is only appropriate if the CSS layout really has those slot widths. If the image is in a 90%-width article column, a grid column, or a container with a maximum width, describe that layout instead. A common pattern for a centered content area with side margins and a maximum width is:

<img
  src="photo-800.jpg"
  srcset="photo-480.jpg 480w, photo-800.jpg 800w, photo-1200.jpg 1200w"
  sizes="(width <= 600px) calc(100vw - 32px), (width <= 900px) calc(100vw - 64px), 800px"
  width="1200"
  height="800"
  alt="A red bicycle leaning against a brick wall"
  class="article-photo"
>
.article-photo {
  display: block;
  width: 100%;
  height: auto;
  max-width: 800px;
}

Here, the slot hint assumes 16 pixels of total horizontal space on narrow viewports, 64 pixels between the viewport and image across the middle range, and an 800-pixel maximum slot on wider screens. Adapt the conditions and calculations to the actual container and CSS.

Use density descriptors only for fixed-size images

If an icon or other image always renders at the same CSS dimensions, you can offer density variants:

<img
  src="avatar-1x.png"
  srcset="avatar-1x.png 1x, avatar-2x.png 2x"
  width="80"
  height="80"
  alt="Jordan Lee"
>

This pattern describes alternatives for a fixed rendered size at different pixel densities. For a fluid photo or other image whose CSS width changes with the viewport, prefer w candidates and sizes. Do not mix x and w descriptors in the same srcset.

3. Use different crops for different layouts

Sometimes shrinking a wide image makes its subject too small or cuts off important detail. Use picture when the narrow layout needs a distinct crop or image. Keep an img element inside it for the fallback and alternative text:

<picture>
  <source media="(width <= 600px)" srcset="portrait-crop-600.jpg">
  <img
    src="wide-image-1200.jpg"
    width="1200"
    height="675"
    alt="A climber reaching for a hold on an indoor climbing wall"
  >
</picture>

The browser evaluates the source conditions and uses the matching source when appropriate; otherwise, the img supplies the fallback. Choose a useful fallback that communicates the same essential information.

If each crop also needs multiple resolutions, add a candidate set to each source and describe its slot width with sizes:

<picture>
  <source
    media="(width <= 600px)"
    srcset="portrait-400.jpg 400w, portrait-600.jpg 600w"
    sizes="100vw"
  >
  <img
    src="wide-1200.jpg"
    srcset="wide-800.jpg 800w, wide-1200.jpg 1200w"
    sizes="(width <= 900px) 100vw, 800px"
    width="1200"
    height="675"
    alt="A climber reaching for a hold on an indoor climbing wall"
  >
</picture>

Use files with the intended crop and check their dimensions and aspect ratios. Different crop ratios can affect layout if the page has not reserved suitable space. If a consistent display box is more important than preserving each file’s intrinsic ratio, define the design deliberately in CSS, for example with a fixed aspect ratio and object-fit: cover; check that the crop still shows the important subject.

4. Prevent layout shifts and support mobile layout

Set the viewport so mobile browsers lay out the page using the device width:

<meta name="viewport" content="width=device-width">

Provide the image’s intrinsic dimensions when they match the intended default ratio:

<img src="photo-800.jpg" width="1200" height="800" alt="A red bicycle leaning against a brick wall">

These dimensions give the browser an aspect ratio to reserve before the file loads. They do not mean the image must render at 1200 by 800 CSS pixels. Let CSS size it responsively:

img {
  display: block;
  max-width: 100%;
  height: auto;
}

For a component with a deliberate ratio, CSS can reserve that ratio on the container or image instead. Make sure the reserved shape matches the selected image and crop at each breakpoint; otherwise, the content may shift or appear unexpectedly cropped when the asset loads.

5. Prepare candidates and check the result

  1. Decide whether the image content stays the same. If yes, use responsive candidates. If a different composition is needed, use art direction with picture.
  2. Export candidates at useful intrinsic widths from the original. Keep the same content and crop for a width-descriptor set. Use separate crop assets for art-directed sources.
  3. Write srcset with accurate w descriptors that match each file’s actual pixel width.
  4. Measure the rendered image slot at relevant viewport widths and translate that layout into a sizes value. Include a sensible final fallback size.
  5. Add real dimensions or reserve the layout aspect ratio, then apply responsive CSS.
  6. Check on narrow, medium, and wide viewports, including a high-density display or device emulation. In browser developer tools, inspect the selected image request and its transferred size. Confirm that the chosen crop and sharpness are right and that the layout does not jump while loading.

Responsive markup cannot create smaller files: the candidate files must exist and be reachable. It also cannot guarantee a particular byte saving, since formats, compression, image content, caching, and the browser’s choice all matter. In one MDN example, an 800-pixel image is 128 KB and a 480-pixel image is 63 KB, a 65 KB difference for that example only. Do not treat that as a universal saving.

6. Troubleshooting

Symptom Likely cause Fix
The browser downloads a file that looks too large for the slot. sizes overstates the rendered width, or the candidate set has no smaller useful file. Compare sizes with the actual CSS slot at that viewport. Add appropriately sized candidates if needed.
The image looks soft on a high-density display. The available candidates do not provide enough pixels for the rendered size and device conditions, or a smaller candidate was selected due to a wrong slot hint. Check the requested file and actual slot width. Provide an adequate larger candidate and correct sizes.
A candidate is missing or returns a failed request. A filename, path, or deployment URL in srcset is wrong or the asset is unavailable. Open each candidate URL directly, fix the path, and verify that deployment includes every file.
The wrong crop appears on a phone. The source media condition does not match the intended breakpoint, or the source file is not the intended crop. Check the condition against the viewport width, inspect the actual file, and keep the img fallback valid.
The page shifts when the image loads. No space was reserved, or the declared dimensions/ratio do not match the displayed asset. Add correct width and height or reserve the intended aspect ratio in CSS, including any crop changes.
Every viewport appears to use the same file. The candidates may be equivalent in width, sizes may not reflect the layout, or caching and inspection may obscure the selected request. Confirm each URL and descriptor, inspect the actual network request after changing viewport, and account for browser caching.
The picture source has no alternative text. Alternative text belongs on its child img, not on source. Put the meaningful alt on the img fallback.

7. Performance, reliability, and cost

Responsive image markup is browser-native and requires no image service to function. Its transfer and rendering benefits depend on supplying suitable assets and accurate hints. A smaller candidate can save bytes on a small slot, while an inaccurate sizes value can defeat that goal. Keep candidates available at stable URLs and retain the img fallback.

Avoid preloading every responsive image by default. Prefer including images in the initial HTML so the browser can discover them, and use preload selectively when there is a clear page-level reason; overusing preload can degrade performance. Responsive image markup itself does not imply an external service charge. If you choose a managed image service, evaluate its transformation, delivery, and pricing terms separately.

8. Or skip the browser setup

If you need screenshots of pages to review responsive layouts or share what a viewport looks like, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It is separate from responsive image delivery: it captures a rendered page rather than generating your site’s srcset assets. Its options include viewport sizes and 12 device presets, full-page capture with lazy images loaded, and image output in PNG, JPEG, or WebP.

One GET request returns a screenshot. See the ScreenshotNeo API documentation for parameters and options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo.

9. FAQ

Does sizes set the image’s CSS width?

No. It tells the browser the expected slot width for candidate selection. CSS determines the rendered layout.

Can I use srcset without sizes?

Yes, density descriptors are useful for fixed rendered sizes. For width-descriptor candidates in a fluid layout, provide sizes so the browser can estimate the slot width.

Should I use picture for every responsive image?

No. Use it when a layout condition needs a different image or crop. Use img with candidates for the same visual at different resolutions.

Do I need a JavaScript resize handler?

No. For these standard responsive image patterns, browser-native markup handles candidate selection and art direction.

Sources