ESC

Type to search the knowledge base.

Responsive Images CSS

CSS techniques for responsive images — max-width, object-fit, art-direction hooks, and how CSS pairs with srcset and sizes.

intermediate3 min read
  • css
  • responsive-images
  • images

Responsive images are a HTML + CSS partnership. HTML (srcset, sizes, <picture>) picks which file to download. CSS decides how the chosen image paints in the layout. Confusing the two causes either huge downloads or broken crops.

Docs: MDN responsive images, object-fit, web.dev images.

Never overflow the container

img,
video {
  max-width: 100%;
  height: auto;
  display: block; /* remove inline baseline gap */
}

This is the baseline. Intrinsic width attributes still help CLS; CSS prevents flex/grid blowouts.

Fit the slot

.card__media {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--surface-2);
}

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top; /* keep faces */
}

Use contain for product logos that must not crop; cover for photography.

Pairing with sizes (conceptual)

<img
  src="/hero-800.jpg"
  srcset="/hero-400.jpg 400w, /hero-800.jpg 800w, /hero-1200.jpg 1200w"
  sizes="(min-width: 48rem) 50vw, 100vw"
  width="1200"
  height="675"
  alt=""
/>

sizes must match layout CSS. If CSS eventually shows the image at full viewport on desktop, lying with 50vw downloads a too-small file (blur) or wastes bandwidth the other way. When you change grid breakpoints, update sizes.

Background images vs content images

.hero {
  background-image: image-set(
    url("/hero.avif") type("image/avif"),
    url("/hero.webp") type("image/webp"),
    url("/hero.jpg") type("image/jpeg")
  );
  background-size: cover;
  background-position: center;
}

Use content <img> when the image is meaningful (alt text, SEO). Use CSS backgrounds for pure decoration. Backgrounds don’t get srcset selection the same way — image-set() helps resolution, not full art direction.

Art direction is HTML

CSS object-position can re-crop slightly; swapping a vertical crop for mobile vs wide landscape is <picture> + media attributes, not a media query on content: url() for primary content.

<picture>
  <source media="(max-width: 40rem)" srcset="/hero-mobile.jpg" />
  <img src="/hero-desktop.jpg" alt="Conference hall" />
</picture>

Performance-minded CSS

.below-fold img {
  content-visibility: auto; /* where appropriate */
}

img[loading="lazy"] {
  /* browser lazy-loads; still reserve aspect-ratio */
  aspect-ratio: attr(width type(<number>)) / attr(height type(<number>)); /* limited support — prefer width/height attrs + CSS ratio */
}

Prefer explicit aspect-ratio matching the asset.

Interview out-loud

“CSS makes images fluid with max-width: 100% and controls cropping with object-fit and aspect-ratio. File selection is HTML srcset/sizes/picture. I keep sizes honest to the CSS layout, use content images for meaningful media, and backgrounds for decoration only.”

Footguns

  1. height: auto missing → stretched images.
  2. sizes lying after a redesign.
  3. Heavy CSS filters on large heroes (decode + paint cost).
  4. Using background-image for captions/SEO content.
  5. Fixed pixel widths fighting fluid grids.

LCP hero checklist

  1. Right format (AV1/AVIF/WebP/JPEG chain).
  2. Honest sizes + adequate srcset.
  3. width/height or CSS aspect-ratio.
  4. Do not lazy-load the LCP image.
  5. Optional fetchpriority="high" on the LCP img.
  6. CSS object-fit only after the resource is chosen correctly.
<img
  src="/hero-1200.jpg"
  srcset="/hero-800.jpg 800w, /hero-1200.jpg 1200w, /hero-1600.jpg 1600w"
  sizes="100vw"
  width="1600"
  height="900"
  alt="…"
  fetchpriority="high"
  decoding="async"
/>

CSS cannot fix a 3MB hero. Optimize assets first; crop second; style third.

Density and art direction split

Use srcset density descriptors for fixed icons; use width descriptors for fluid photos; use <picture> when the crop changes. CSS image-set() helps with background resolution switching but still lacks the full sizes negotiation of content images. Keep the decision tree in the component docs so designers request the right asset package (one crop vs many).

Further reading

Related guides