Ad – 728×90
📱 Responsive Design

Responsive Images – CSS and HTML Techniques

Images are the biggest performance bottleneck on most websites. Serving a 2000px image to a 375px phone screen wastes bandwidth and slows down the page. Responsive images solve this — serving the right image size to the right device, maintaining correct proportions, and loading only when needed. This lesson covers both the CSS properties (object-fit, aspect-ratio) and the HTML attributes (srcset, sizes, picture) that make images truly responsive.

⏱️ 20 min read 🎯 Beginner 📅 Updated 2026 👁️ Lesson 2 of 4

The Fluid Image Baseline

The single most important CSS rule for responsive images — include it in every project:

CSS – Fluid image reset
img, video, canvas, svg {
  max-width: 100%;  /* never wider than container */
  height: auto;     /* maintain aspect ratio */
  display: block;   /* remove inline gap below image */
}

max-width: 100% lets images shrink below their natural size but never grow beyond it. height: auto maintains the original aspect ratio as width changes.

object-fit – Controlling Image Display in a Box

object-fit controls how a replaced element (<img>, <video>) fills its container — the same way background-size works for background images.

CSS – object-fit
/* fill — stretches to fill (default, may distort) */
img { object-fit: fill; }

/* cover — fills while maintaining ratio, may crop */
img { object-fit: cover; }

/* contain — fits entirely inside, may have empty space */
img { object-fit: contain; }

/* none — original size, clipped if overflows */
img { object-fit: none; }

/* scale-down — whichever of none/contain is smaller */
img { object-fit: scale-down; }

/* Most common pattern: fixed-size image thumbnail */
.avatar {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  object-fit: cover;    /* crop to circle, no distortion */
}

/* Card image with fixed height */
.card-image {
  width: 100%;
  height: 220px;
  object-fit: cover;    /* always fills the height, crops sides */
}
▶ object-fit: cover on a fixed-size container
cover: fills box
contain: fits inside

object-position – Focal Point Control

CSS – object-position
/* Default: center center */
img { object-fit: cover; object-position: center; }

/* Position the image within its box */
img { object-position: top; }           /* show top of image */
img { object-position: bottom right; }  /* show bottom-right of image */
img { object-position: 20% 30%; }       /* 20% from left, 30% from top */

/* Person portrait — keep face visible when cropping */
.person-photo {
  object-fit: cover;
  object-position: top center;  /* prioritize the face at the top */
}
Ad – 336×280

aspect-ratio – Prevent Layout Shift

Setting a fixed aspect ratio reserves space for an image before it loads — preventing Cumulative Layout Shift (CLS), a Core Web Vital metric.

CSS – aspect-ratio
/* aspect-ratio: width / height */
.hero-image { aspect-ratio: 16 / 9; }
.thumbnail  { aspect-ratio: 4 / 3; }
.avatar     { aspect-ratio: 1 / 1; }   /* square */
.banner     { aspect-ratio: 3 / 1; }   /* wide banner */

/* Combined with object-fit for responsive images */
.card-image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* Reserve space before image loads (prevents CLS) */
img {
  width: 100%;
  aspect-ratio: attr(width) / attr(height);  /* uses HTML width/height attrs */
}
💡
Always set width and height on <img> tags

Add width and height attributes to every <img> tag matching the image's natural dimensions. The browser uses these to reserve the correct space before the image loads, eliminating layout shift. With height: auto in CSS, the image still scales responsively — the attributes are just hints for the browser.

srcset – Serving Different Resolutions

The HTML srcset attribute lets you provide multiple image files for different screen sizes or resolutions. The browser picks the most appropriate one.

HTML – srcset for resolution switching
<!-- Width descriptors — browser chooses based on display width and DPR -->
<img
  src="hero-800.jpg"
  srcset="
    hero-400.jpg  400w,
    hero-800.jpg  800w,
    hero-1200.jpg 1200w,
    hero-1600.jpg 1600w
  "
  sizes="
    (max-width: 600px) 100vw,
    (max-width: 1200px) 80vw,
    1200px
  "
  alt="Hero image"
  width="1200"
  height="675"
  loading="lazy"
>

<!-- DPR (device pixel ratio) descriptors — for retina screens -->
<img
  src="logo.png"
  srcset="logo.png 1x, logo@2x.png 2x, logo@3x.png 3x"
  alt="ylearner"
  width="160"
  height="40"
>

The <picture> Element – Art Direction

Use <picture> when you want to show a different image crop or composition at different screen sizes — not just different resolutions of the same image.

HTML – picture element
<picture>
  <!-- WebP for modern browsers (smaller file size) -->
  <source
    type="image/webp"
    srcset="hero-mobile.webp 400w, hero-desktop.webp 1200w"
    sizes="(max-width: 768px) 100vw, 1200px"
  >

  <!-- JPEG fallback -->
  <source
    type="image/jpeg"
    srcset="hero-mobile.jpg 400w, hero-desktop.jpg 1200w"
    sizes="(max-width: 768px) 100vw, 1200px"
  >

  <!-- Fallback img (always required) -->
  <img src="hero-desktop.jpg" alt="Hero" width="1200" height="600" loading="lazy">
</picture>

<!-- Art direction: different crop on mobile -->
<picture>
  <source media="(max-width: 767px)" srcset="team-portrait.jpg">
  <source media="(min-width: 768px)" srcset="team-landscape.jpg">
  <img src="team-landscape.jpg" alt="The team" width="1200" height="630">
</picture>

Lazy Loading

HTML – Lazy loading
<!-- Native lazy loading — supported in all modern browsers -->
<img src="image.jpg" alt="..." loading="lazy">

<!-- eager — load immediately (use for above-the-fold images) -->
<img src="hero.jpg" alt="..." loading="eager">

<!-- fetchpriority — hint for above-fold images (LCP) -->
<img src="hero.jpg" alt="..." fetchpriority="high" loading="eager">
💡
Never lazy-load the LCP image

The Largest Contentful Paint (LCP) image — usually the hero or first visible image — should have loading="eager" and fetchpriority="high". Lazy-loading it delays the page's most important visual element and hurts your Core Web Vitals score. Only use loading="lazy" on images below the fold.

Modern Image Formats

Format comparison
FORMAT     COMPRESSION  TRANSPARENCY  ANIMATION  BROWSER SUPPORT
JPEG       Lossy        No            No         Universal
PNG        Lossless     Yes           No         Universal
GIF        Lossless     1-bit         Yes        Universal (avoid — use WebP/AVIF)
WebP       Lossy/Loss.  Yes           Yes        All modern browsers (2020+)
AVIF       Lossy/Loss.  Yes           Yes        Chrome/Firefox/Safari (2022+)
SVG        Vector       Yes           Yes        Universal

RECOMMENDATION:
- Photos:     WebP (primary) + JPEG (fallback via <picture>)
- Icons/UI:   SVG (scalable, tiny file size)
- Screenshots: WebP or PNG
- Animations: WebP or CSS animations (not GIF)
- Cutting edge: AVIF (50% smaller than WebP for photos)

📋 Summary

  • Fluid baseline: img { max-width: 100%; height: auto; display: block; }
  • object-fit: cover — fills fixed-size container without distortion, crops if needed.
  • object-position — controls crop focal point (default: center).
  • aspect-ratio — reserves space before image loads, prevents layout shift.
  • srcset + sizes — serve different resolutions; browser picks the best one.
  • <picture> — serve different crops (art direction) or different formats (WebP/JPEG).
  • loading="lazy" — defer off-screen images. Use eager for above-fold.
  • fetchpriority="high" — prioritize the LCP image.
  • WebP — use as primary format for photos. Smaller than JPEG, transparent like PNG.

Frequently Asked Questions

What is the difference between object-fit and background-size? +

They work the same way but apply to different things. object-fit applies to replaced elements — <img>, <video>, <canvas> — controlling how the element's content fills its box. background-size applies to CSS background images. Both support the same values: cover, contain, explicit sizes. Use <img> with object-fit for content images (accessible, indexable by search engines, can be lazy-loaded). Use background-image for purely decorative images.

Should I use srcset or the picture element? +

Use srcset + sizes (on a regular <img>) when you have the same image at different resolutions — the browser picks the best size for the screen. Use <picture> when: (1) you want to serve different image formats (WebP with JPEG fallback), or (2) you want art direction — a different crop or composition at different screen sizes. In practice, most images need srcset for resolution switching and picture for format selection.

How do I prevent layout shift from images? +

Three things: (1) Always set width and height attributes on <img> tags matching the image's natural dimensions. (2) Add height: auto in your CSS reset so the image still scales responsively. (3) Optionally add aspect-ratio in CSS as a backup. The browser uses the HTML dimensions to reserve the correct space in the layout before the image loads, eliminating the reflow that causes CLS.