CSS Responsive Images

Responsive images look sharp on every screen — from a small phone to a 4K monitor — while loading only as much image data as the device actually needs. A phone does not need to download a 3000px-wide image to display it at 375px wide. Responsive image techniques solve this without sacrificing quality.

The Core CSS Rule

This is the starting point for every responsive image:

img {
  max-width: 100%;
  height: auto;
}
DIAGRAM — max-width: 100% behavior:

Image natural size: 1200px

On a 1440px screen: image displays at 1200px (its natural size — no upscale)
On a 900px screen:  image scales to 900px (fits the container)
On a 375px screen:  image scales to 375px (fits the phone screen)

Image never overflows its container, never distorts.

width: 100% vs max-width: 100%

DIAGRAM — Comparison:

img { width: 100%; }
→ Always fills 100% of the container.
  A 100px image in a 1000px container stretches to 1000px — pixelated!

img { max-width: 100%; }
→ Fills the container up to the image's natural size.
  A 100px image in a 1000px container stays at 100px — crisp!

Use max-width: 100% for content images. Use width: 100% only when you deliberately want the image to fill the container at all sizes, paired with object-fit: cover to avoid stretching.

The srcset Attribute — Different Resolutions

HTML's srcset attribute lets you offer multiple image files at different resolutions. The browser picks the best one for the device.

<img
  src="photo-800.jpg"
  srcset="photo-400.jpg 400w,
          photo-800.jpg 800w,
          photo-1600.jpg 1600w"
  alt="Mountain view"
>
DIAGRAM — srcset decision:

Phone (375px screen, 2x pixel ratio):
  Needs: 375 × 2 = 750px wide image
  Browser picks: photo-800.jpg ← closest fit

Desktop (1440px screen, 1x pixel ratio):
  Needs: 1440px wide image
  Browser picks: photo-1600.jpg ← closest fit

Browser downloads only what it needs — no wasted data.

The sizes Attribute — Layout Hints

sizes tells the browser how wide the image will display at different breakpoints, so it picks the right file from srcset.

<img
  src="photo-800.jpg"
  srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w"
  sizes="(max-width: 600px) 100vw,
         (max-width: 1024px) 50vw,
         800px"
  alt="Mountain view"
>
DIAGRAM — sizes tells the browser the image's display width:

Screen 400px wide  → sizes says "100vw" = 400px display width
Screen 800px wide  → sizes says "50vw"  = 400px display width
Screen 1200px wide → sizes says "800px" = 800px display width

Browser combines this with srcset to pick the optimal file.

The picture Element — Art Direction

The <picture> element lets you show a completely different image crop or composition on different screen sizes — not just a different resolution of the same image.

<picture>
  <source media="(max-width: 600px)"  srcset="photo-portrait.jpg">
  <source media="(max-width: 1024px)" srcset="photo-square.jpg">
  <img src="photo-landscape.jpg" alt="Coastal town">
</picture>
DIAGRAM — Art direction with picture:

Phone (portrait):
  ┌──────┐
  │ 📸   │   ← photo-portrait.jpg: tight vertical crop
  │ crop │      (faces or key subject fills the frame)
  └──────┘

Tablet (square):
  ┌────────┐
  │  📸📸  │  ← photo-square.jpg: medium crop
  └────────┘

Desktop (landscape):
  ┌──────────────────────┐
  │     📸📸📸📸📸       │  ← full landscape photo
  └──────────────────────┘

Modern Image Formats with picture

Use <picture> to serve modern formats (WebP, AVIF) to browsers that support them, with a JPEG fallback.

<picture>
  <source type="image/avif" srcset="photo.avif">
  <source type="image/webp" srcset="photo.webp">
  <img src="photo.jpg" alt="Description">
</picture>
DIAGRAM — Format fallback chain:

Browser supports AVIF? → YES → use photo.avif (smallest file)
Browser supports WebP? → YES → use photo.webp (smaller than JPEG)
Fallback               →       use photo.jpg (universal support)

File Size Comparison (same image)

FormatRelative File SizeBrowser Support
JPEG100% (baseline)All browsers
WebP~65% of JPEGAll modern browsers
AVIF~50% of JPEGChrome, Firefox, Safari (2023+)

Responsive Background Images

For CSS background images, use @media queries to swap image sources at different breakpoints.

.hero {
  background-image: url("hero-mobile.jpg");
  background-size: cover;
  background-position: center;
}

@media (min-width: 600px) {
  .hero {
    background-image: url("hero-tablet.jpg");
  }
}

@media (min-width: 1024px) {
  .hero {
    background-image: url("hero-desktop.jpg");
  }
}

High-DPI Screens (Retina) with CSS

Retina and high-DPI displays use 2x or 3x more physical pixels than standard screens. Images look blurry at 1x. Use the resolution media query to serve sharper images.

.logo {
  background-image: url("logo.png");
  background-size: 120px 40px;
}

@media (min-resolution: 2dppx) {
  .logo {
    background-image: url("logo@2x.png"); /* 2× the pixel density */
  }
}

Lazy Loading

Load offscreen images only when the user scrolls near them. This is a single HTML attribute — no CSS needed.

<img src="photo.jpg" alt="Description" loading="lazy">

Combine this with a CSS placeholder color so users see a smooth colored box while the image loads:

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

Responsive Image Checklist

TechniqueWhen to Use It
max-width: 100%; height: autoEvery image on the page
srcset with width descriptorsServing different sizes of the same image
sizes attributePaired with srcset for accurate selection
picture + sourceDifferent crops per screen, or modern formats
@media background swapCSS background images
loading="lazy"All images below the fold
AVIF/WebP via pictureReducing page weight for all users

Responsive images improve page speed, reduce mobile data usage, and ensure content looks sharp on high-DPI screens. The max-width: 100% rule handles the basics; srcset, sizes, and <picture> handle the advanced optimization.

Leave a Comment

Your email address will not be published. Required fields are marked *