~/hackweb.dev
Responsive Images
Quiz
...

Responsive Images

beginner · updated Tue Sep 08 2026Contribute

Master srcset, picture element, and art direction for modern images.

Responsive Images

Responsive images load different sizes based on screen size and device capabilities. This improves performance and user experience.

Why Responsive Images?

  • Performance — Don’t load 4K images on mobile
  • Bandwidth — Save data on slow connections
  • Quality — Serve appropriate resolution for each device
  • Art Direction — Show different crops per screen size

Basic srcset

The srcset attribute offers multiple image versions:

<img
  src="photo-800.jpg"
  srcset="
    photo-400.jpg 400w,
    photo-800.jpg 800w,
    photo-1200.jpg 1200w
  "
  alt="Responsive image"
/>

How it works:

  • Browser chooses best image based on screen size
  • 400w, 800w, 1200w = image width in pixels
  • Browser calculates which image fits best

Sizes Attribute

Tell the browser how wide the image will display:

<img
  src="photo-800.jpg"
  srcset="
    photo-400.jpg 400w,
    photo-800.jpg 800w,
    photo-1200.jpg 1200w
  "
  sizes="(max-width: 600px) 100vw, 800px"
  alt="Responsive image"
/>

Sizes syntax:

  • (max-width: 600px) 100vw — On mobile, image is 100% of viewport
  • 800px — On desktop, image is 800px wide

Why sizes matters:

  • Browser needs to know display size BEFORE loading image
  • Without sizes, browser can’t choose optimal image

Complete srcset Example

<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: 480px) 100vw,
    (max-width: 1024px) 50vw,
    800px
  "
  alt="Hero image that adapts to screen size"
  loading="lazy"
  width="1600"
  height="900"
/>

Breakdown:

  • Mobile (< 480px): Loads 400w image
  • Tablet (< 1024px): Loads 800w image
  • Desktop: Loads 1200w or 1600w image

Retina Displays (HiDPI)

Serve higher resolution for retina screens:

<img
  src="logo-200.jpg"
  srcset="
    logo-200.jpg 1x,
    logo-400.jpg 2x,
    logo-600.jpg 3x
  "
  alt="Logo"
/>

Resolution descriptors:

  • 1x — Standard resolution
  • 2x — Retina (2x pixels)
  • 3x — Super retina (3x pixels)

Picture Element

For art direction (different crops per screen size):

<picture>
  <!-- Desktop: wide crop -->
  <source media="(min-width: 1024px)" srcset="hero-wide.jpg" />

  <!-- Tablet: medium crop -->
  <source media="(min-width: 600px)" srcset="hero-medium.jpg" />

  <!-- Mobile: square crop -->
  <img src="hero-square.jpg" alt="Hero image" />
</picture>

When to use picture:

  • Different crops per device
  • Different focal points
  • Showing/hiding elements
  • Art direction control

Picture with Format Selection

Serve modern formats to supporting browsers:

<picture>
  <!-- Modern browsers: WebP -->
  <source type="image/webp" srcset="photo.webp" />

  <!-- Fallback: JPEG -->
  <img src="photo.jpg" alt="Photo" />
</picture>

Format support:

  • WebP: Chrome, Firefox, Edge, Safari 14+
  • AVIF: Chrome, Firefox (better compression)
  • JPEG: Universal fallback

Complete Picture Example

<picture>
  <!-- Desktop: wide landscape -->
  <source
    media="(min-width: 1024px)"
    type="image/webp"
    srcset="hero-wide.webp"
  />
  <source media="(min-width: 1024px)" srcset="hero-wide.jpg" />

  <!-- Tablet: medium crop -->
  <source
    media="(min-width: 600px)"
    type="image/webp"
    srcset="hero-medium.webp"
  />
  <source media="(min-width: 600px)" srcset="hero-medium.jpg" />

  <!-- Mobile: square crop -->
  <source type="image/webp" srcset="hero-square.webp" />
  <img src="hero-square.jpg" alt="Hero image" width="800" height="800" />
</picture>

Loading Strategies

Lazy Loading

Load images only when visible:

<img src="photo.jpg" loading="lazy" alt="Lazy loaded" />

When to use:

  • Images below the fold
  • Image galleries
  • Long pages with many images

Eager Loading

Load images immediately (default):

<img src="photo.jpg" loading="eager" alt="Eager loaded" />

When to use:

  • Above-the-fold images
  • Hero images
  • Critical content

Complete Example

Here’s a responsive hero section:

<section class="hero">
  <picture>
    <!-- Desktop: wide crop -->
    <source
      media="(min-width: 1024px)"
      type="image/webp"
      srcset="hero-wide.webp"
    />
    <source media="(min-width: 1024px)" srcset="hero-wide.jpg" />

    <!-- Mobile: square crop -->
    <source type="image/webp" srcset="hero-square.webp" />
    <img
      src="hero-square.jpg"
      alt="Person learning web development"
      loading="eager"
      width="1200"
      height="600"
    />
  </picture>

  <div class="hero-content">
    <h1>Learn Web Development</h1>
    <p>Start your journey today</p>
  </div>
</section>

<section class="gallery">
  <h2>Gallery</h2>
  <div class="grid">
    <!-- Lazy load gallery images -->
    <img
      src="gallery-400.jpg"
      srcset="
        gallery-400.jpg 400w,
        gallery-800.jpg 800w
      "
      sizes="(max-width: 600px) 100vw, 400px"
      alt="Gallery image 1"
      loading="lazy"
    />
    <img
      src="gallery-400.jpg"
      srcset="
        gallery-400.jpg 400w,
        gallery-800.jpg 800w
      "
      sizes="(max-width: 600px) 100vw, 400px"
      alt="Gallery image 2"
      loading="lazy"
    />
  </div>
</section>

Best Practices

  1. Always provide srcset — Let browser choose optimal image
  2. Use sizes attribute — Helps browser calculate before loading
  3. Lazy load below fold — Improve initial page load
  4. Serve modern formats — WebP/AVIF with JPEG fallback
  5. Set width and height — Prevents layout shift (CLS)

Common Mistakes

  1. Missing sizes attribute — Browser can’t choose optimal image
  2. Not providing fallback src — Required for accessibility
  3. Lazy loading hero image — Above fold should load immediately
  4. Ignoring retina screens — Serve 2x for crisp images
  5. Same image for all devices — Wastes bandwidth on mobile