Skip to content

Responsive Images — Complete Guide

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Responsive Images. We cover key concepts, practical examples, and best practices to help you master this topic.

Responsive images use srcset, sizes, and the picture element to serve appropriate image resolutions, formats (WebP, AVIF), and crops based on viewport size, device pixel ratio, and network conditions.

What You'll Learn

  • The srcset and sizes attributes for resolution switching
  • The picture element for art direction
  • Modern image formats: WebP, AVIF
  • Lazy loading and decoding hints
  • Responsive background images
  • Image performance optimization

Why It Matters

  • Images are the largest page weight contributor
  • Serving desktop images to mobile wastes bandwidth
  • Retina displays need 2x-3x resolution images
  • Proper responsive images improve performance and SEO

Real-World Use

  • An e-commerce site serves different product image resolutions per device
  • A news site uses art direction (crops) for different viewports
  • A portfolio uses next-gen formats with fallbacks
  • A travel site lazy loads images below the fold
flowchart LR
  A[Responsive Images] --> B[Resolution]
  A --> C[Art Direction]
  A --> D[Format Selection]
  B --> E[srcset + sizes]
  C --> F[picture element]
  D --> G[WebP/AVIF with JPEG fallback]
  E --> H[Right Size]
  F --> I[Right Crop]
  G --> J[Smallest File]

Understanding Responsive Images

Responsive images solve three problems:

  1. Resolution — Serve 1x images to standard displays, 2x to retina displays
  2. Art direction — Serve different crops for different viewport sizes
  3. Format — Serve modern formats (WebP, AVIF) with backward-compatible fallbacks

Resolution Switching with srcset

The srcset attribute lists multiple image files with their widths or pixel densities. The sizes attribute tells the browser how much space the image will occupy at different viewport widths.

Code Example: srcset and sizes

<!-- Simple resolution switching (density descriptors) -->
<img src="photo-1x.jpg"
     srcset="photo-1x.jpg 1x, photo-2x.jpg 2x, photo-3x.jpg 3x"
     alt="Mountain landscape at sunrise">

<!-- Width descriptors (more powerful) -->
<img src="photo-800.jpg"
     srcset="photo-400.jpg 400w,
             photo-800.jpg 800w,
             photo-1200.jpg 1200w,
             photo-1600.jpg 1600w"
     sizes="(max-width: 600px) 100vw,
            (max-width: 1024px) 50vw,
            33vw"
     alt="Mountain landscape at sunrise">

<!-- Explanation:
     - On a 400px phone: 100vw = 400px. Browser might pick photo-400.jpg (or 800.jpg at 2x)
     - On a 768px tablet: 50vw = 384px. Browser picks photo-400.jpg
     - On a 1440px desktop: 33vw = 475px. Browser picks photo-800.jpg
-->

Expected output: The browser automatically selects the most appropriate image source based on viewport size and device pixel ratio. A 1x display on a 400px phone gets photo-400.jpg (about 400px). A 2x retina display at 1200px gets photo-1200.jpg.

Code Example: Art Direction with picture

<!-- Art direction: different crops for different viewports -->
<picture>
    <source media="(max-width: 480px)"
            srcset="hero-mobile.jpg"
            sizes="100vw">
    <source media="(max-width: 768px)"
            srcset="hero-tablet.jpg"
            sizes="100vw">
    <source media="(min-width: 769px)"
            srcset="hero-desktop.jpg, hero-desktop-2x.jpg 2x"
            sizes="100vw">
    <img src="hero-desktop.jpg"
         alt="Team of engineers collaborating in a modern office space"
         loading="lazy">
</picture>

<!-- Format selection with fallback -->
<picture>
    <source type="image/avif" srcset="photo.avif">
    <source type="image/webp" srcset="photo.webp">
    <img src="photo.jpg"
         alt="Handcrafted ceramic vase on wooden table"
         loading="lazy"
         decoding="async">
</picture>

<!-- Combined: art direction + format + resolution -->
<picture>
    <source media="(max-width: 480px)"
            type="image/webp"
            srcset="product-mobile.webp, product-mobile-2x.webp 2x">
    <source media="(max-width: 480px)"
            type="image/jpeg"
            srcset="product-mobile.jpg, product-mobile-2x.jpg 2x">
    <source media="(min-width: 481px)"
            type="image/webp"
            srcset="product-desktop.webp, product-desktop-2x.webp 2x">
    <source media="(min-width: 481px)"
            type="image/jpeg"
            srcset="product-desktop.jpg, product-desktop-2x.jpg 2x">
    <img src="product-desktop.jpg"
         alt="Blue ceramic vase with white floral pattern, 12 inches tall"
         loading="lazy"
         width="800"
         height="600">
</picture>

Expected output: The phone gets a close-up crop of the product (product-mobile.jpg). Desktop gets the full product shot. Browsers that support AVIF get the smallest file. WebP-supporting browsers get WebP. Older browsers get JPEG.

Code Example: Responsive Background Images

/* Responsive background images with media queries */
.hero {
    background-image: url('hero-mobile.jpg');
    background-size: cover;
    background-position: center;
    min-height: 50vh;
}

@media (min-width: 768px) {
    .hero {
        background-image: url('hero-tablet.jpg');
        min-height: 60vh;
    }
}

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

/* Using image-set for resolution switching */
.logo {
    background-image: image-set(
        'logo-1x.png' 1x,
        'logo-2x.png' 2x,
        'logo-3x.png' 3x
    );
    background-size: contain;
    background-repeat: no-repeat;
    width: 200px;
    height: 50px;
}

/* Lazy loading background images */
.lazy-bg {
    background-image: none;
    transition: background-image 0.3s;
}

.lazy-bg.loaded {
    background-image: url('photo.jpg');
}

Expected output: The hero image changes crop based on viewport width. Mobile shows the most important portion of the image. Desktop shows the full scene. Logo uses the appropriate resolution for the device's pixel density.

Common Mistakes

  1. Not using responsive images — Serving a 2400px hero image to a 375px phone wastes 90 percent of bandwidth.
  2. Wrong sizes attribute — If sizes is omitted or wrong, the browser guesses incorrectly. Always provide accurate sizes.
  3. Missing width and height attributes — Without width/height, the browser cannot reserve space, causing layout shifts (CLS).
  4. No format fallback — Serving only WebP without a JPEG fallback breaks on older browsers.
  5. No lazy loading below the fold — Loading all images immediately wastes bandwidth on images the user may never see.
  6. Overly complex picture elements — Each source adds bytes. Only add variants that provide meaningful savings.
  7. Not optimizing images before serving — Use image CDNs or build-time optimization to compress JPEG/WebP/AVIF appropriately.

Practice Questions

  1. What is the difference between srcset with density descriptors (1x, 2x) and width descriptors (400w, 800w)? Density descriptors are for the same image at different resolutions. Width descriptors allow the browser to pick based on both viewport size and pixel density.
  2. What does the sizes attribute do in responsive images? It tells the browser how much space the image will occupy at different viewport widths, helping it select the right source from srcset.
  3. When should you use the picture element instead of srcset? Use picture for art direction (different crops/ratios per viewport) and format selection (WebP/AVIF with fallbacks).
  4. What is the purpose of the loading="lazy" attribute? It defers loading of off-screen images until the user scrolls near them, saving bandwidth and improving initial page load.
  5. Challenge: Create a responsive image Strategy for a product detail page. Include: a hero product image with art direction (different crops for mobile/tablet/desktop), thumbnail gallery with resolution switching, and a diagram/infographic with format switching (WebP + JPEG fallback). Use srcset, sizes, picture, and lazy loading. Test on 3 different viewport sizes and 2x/1x displays.

FAQ

Do I need to provide every image size option?

No. Provide 3-5 well-chosen sizes. Common breakpoints are 400w, 800w, 1200w, and 1600w. Image CDNs can generate these automatically.

What is the best image format for the web?

AVIF offers the best compression (about 50 percent smaller than JPEG). WebP is more widely supported. JPEG is the universal fallback.

{{< faq "Does lazy loading affect SEO?" "No. Google crawls lazy-loaded images as long as they are in the HTML and not loaded via JavaScript. loading=\"lazy\" is respected by search engines." >}}
What is cumulative layout shift (CLS) and how do images affect it?

CLS measures visual stability. Images without width/height attributes cause layout shifts when they load. Always set width and height on images.

Can I use srcset with background images?

No. Use the picture element for HTML images or media queries with CSS background-image for background images.

Mini Project

Build a responsive image gallery page. Include: a hero image with art direction (3 crops via picture), a grid of 12 thumbnail images (using srcset with 400w, 800w, 1200w variants), a lightbox that loads high-resolution images on demand, lazy loading for all below-fold images, WebP format with JPEG fallback, and proper width/height attributes on all images. Use an image CDN or generate the image variants yourself. Test performance with Chrome DevToolsk "DevTools" >}} Network panel and verify correct image selection at multiple viewport sizes and pixel densities.

What's Next

Continue with Lesson 10: Responsive Navigation to learn how to create navigation that works on any screen size.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro