CSSResponsive Images

Responsive Images

"Responsive images" covers two genuinely different problems that are easy to conflate: making an image fit its container correctly with CSS, and serving the right file for a given screen with HTML. This page focuses on the CSS side — sizing, cropping, and preventing layout shift — and clarifies where the HTML-side mechanism takes over.

The Classic Baseline Fix: max-width: 100%

Without any CSS, an <img> renders at its natural pixel dimensions, happily overflowing a narrower container. The single most important responsive-image rule fixes that in one line:

CSS
img {
  max-width: 100%;
  height: auto; /* preserves aspect ratio as width shrinks */
  display: block; /* removes inline-element whitespace gaps */
}

max-width: 100% lets the image shrink to fit a narrow container while never exceeding its own natural size — it won't stretch a small image larger than it actually is. height: auto is essential alongside it; without it, the image's height stays fixed while its width shrinks, distorting the aspect ratio.

object-fit & object-position

Once an image has to fill a container with a fixed size or aspect ratio (a thumbnail grid, a hero banner), max-width: 100% alone isn't enough — you need control over how the image crops or letterboxes. See the full breakdown on the object-fit & object-position page; the short version:

CSS
.thumbnail {
  width: 100%;
  height: 200px; /* a fixed box the image must fill */
  object-fit: cover;        /* crop to fill, preserving aspect ratio */
  object-position: center;  /* which part of the image stays visible */
}
aspect-ratio: Preventing Layout Shift

Images that load asynchronously collapse to zero height until they arrive, then suddenly push the rest of the page down — a major contributor to poor Cumulative Layout Shift scores. Recap: aspect-ratio reserves the image's final space immediately, before the file has even downloaded.

CSS
img.hero {
  width: 100%;
  aspect-ratio: 16 / 9; /* space is reserved instantly, no layout shift */
  object-fit: cover;
}

HTML
<img
  class="hero"
  src="banner.jpg"
  width="1600"
  height="900"
  alt="Descriptive text"
/>

Setting width and height attributes in the HTML (even though CSS overrides the rendered size) gives the browser the image's intrinsic aspect ratio before any CSS or the image file itself has loaded — modern browsers use these attributes to compute a default aspect-ratio automatically, which is a good belt-and-suspenders habit even when you also set aspect-ratio explicitly in CSS.

What srcset / sizes Handle Instead
A different, complementary mechanism
`srcset` and `sizes` are HTML attributes on `<img>` (or `<source>` inside `<picture>`) — not CSS. They let the browser choose, per user's device and screen, *which image file* to download from a list of candidates at different resolutions, so a phone doesn't have to download the same 4000px-wide file a 4K monitor needs. CSS sizing (this page) then determines how that chosen file gets laid out. Both matter for real production images; they solve different problems and work together.

HTML
<img
  src="photo-800.jpg"
  srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w"
  sizes="(min-width: 1024px) 50vw, 100vw"
  alt="Descriptive text"
  style="max-width: 100%; height: auto;"
/>
Putting It Together
  • max-width: 100%; height: auto; — the non-negotiable baseline for any inline image that should never overflow its container.

  • object-fit / object-position — when the image must fill a fixed-size box exactly, with controlled cropping.

  • aspect-ratio (plus HTML width/height) — reserve layout space before the image loads, avoiding shift.

  • srcset / sizes — a separate, HTML-level optimization for serving the right file size, orthogonal to how CSS lays the chosen image out.

Next
See how these same sizing ideas extend to component-level layout decisions: [Container Queries (@container)](/css/container-queries).