Skip to content

Mobile-First Images — Complete Guide

DodaTech Updated 2026-06-28 6 min read

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

Mobile-first images use srcset, sizes, WebP, Lazy Loading, responsive art direction, and proper aspect ratios for performance and visual quality.

What You'll Learn

  • The srcset and sizes attributes
  • Responsive art direction with picture element
  • Modern image formats (WebP, AVIF)
  • Lazy loading for below-fold images
  • Aspect ratio containers to prevent CLS
  • Background images for mobile
  • Image optimization workflow

Why It Matters

  • Images are the largest assets on most pages
  • Mobile networks are slower and more expensive
  • Wrong image size wastes bandwidth
  • Images without dimensions cause layout shifts

Real-World Use

  • An e-commerce site serves 400px images on mobile, 1200px on desktop
  • A news site uses WebP with JPEG fallback
  • A travel site crops photos differently for mobile
  • A blog lazy loads images, improving initial load
flowchart LR
  A[Mobile-First Images] --> B[srcset]
  A --> C[Picture Element]
  A --> D[Lazy Loading]
  A --> E[Aspect Ratio]
  B --> F[Resolution switching]
  C --> G[Art direction]
  D --> H[loading=lazy]
  E --> I[aspect-ratio CSS]

Responsive Images

Code Example: srcset and sizes

<!-- Mobile-first: smallest image is default -->
<img
    src="photo-400.jpg"
    srcset="
        photo-400.jpg 400w,
        photo-800.jpg 800w,
        photo-1200.jpg 1200w,
        photo-1600.jpg 1600w
    "
    sizes="
        (max-width: 480px) 100vw,
        (max-width: 768px) 90vw,
        (max-width: 1024px) 70vw,
        800px
    "
    alt="Descriptive text describing the image content"
    width="800"
    height="600"
    loading="lazy"
    decoding="async"
>

<!-- Combined pixel density and width -->
<img
    src="photo-400.jpg"
    srcset="
        photo-400.jpg 400w,
        photo-400-2x.jpg 400w 2x,
        photo-800.jpg 800w,
        photo-800-2x.jpg 800w 2x,
        photo-1200.jpg 1200w
    "
    sizes="
        (max-width: 600px) 100vw,
        800px
    "
    alt="Descriptive text"
    width="800"
    height="600"
    loading="lazy"
>

Expected output: The browser selects the appropriate image based on viewport width, pixel density, and network conditions. On a 375px phone with 2x display, it may load photo-800.jpg (400w * 2x = 800w equivalent).

Code Example: Art Direction with Picture

<!-- Art direction: different crops for different screens -->
<picture>
    <!-- Mobile: tight crop, portrait -->
    <source
        media="(max-width: 480px)"
        srcset="
            hero-mobile.webp 480w,
            hero-mobile-2x.webp 960w
        "
        sizes="100vw"
        type="image/webp"
    >
    <source
        media="(max-width: 480px)"
        srcset="
            hero-mobile.jpg 480w,
            hero-mobile-2x.jpg 960w
        "
        sizes="100vw"
        type="image/jpeg"
    >

    <!-- Tablet: medium crop -->
    <source
        media="(max-width: 768px)"
        srcset="
            hero-tablet.webp 768w,
            hero-tablet-2x.webp 1536w
        "
        sizes="100vw"
        type="image/webp"
    >
    <source
        media="(max-width: 768px)"
        srcset="
            hero-tablet.jpg 768w,
            hero-tablet-2x.jpg 1536w
        "
        sizes="100vw"
        type="image/jpeg"
    >

    <!-- Desktop: wide crop, landscape -->
    <source
        srcset="
            hero-desktop.webp 1200w,
            hero-desktop-2x.webp 2400w
        "
        sizes="100vw"
        type="image/webp"
    >
    <source
        srcset="
            hero-desktop.jpg 1200w,
            hero-desktop-2x.jpg 2400w
        "
        sizes="100vw"
        type="image/jpeg"
    >

    <!-- Fallback for older browsers -->
    <img
        src="hero-desktop.jpg"
        alt="Hero banner showing the main value proposition"
        width="1200"
        height="600"
        loading="eager"
        fetchpriority="high"
        decoding="async"
    >
</picture>

Expected output: Mobile users see a tightly-cropped portrait version of the hero image. Desktop users see a wide landscape crop. The browser chooses the best format (WebP if supported, JPEG otherwise).

Code Example: Aspect Ratio Containers

<!-- Fixed aspect ratio: prevents CLS -->
<div class="image-container" style="aspect-ratio: 16 / 9;">
    <img
        src="photo.jpg"
        alt="Descriptive text"
        width="800"
        height="450"
        loading="lazy"
        style="width: 100%; height: 100%; object-fit: cover;"
    >
</div>

<!-- Legacy padding-bottom hack (fallback) -->
<div class="image-container-legacy">
    <img
        src="photo.jpg"
        alt="Descriptive text"
        loading="lazy"
    >
</div>

<style>
/* Modern: aspect-ratio property */
.image-container {
    width: 100%;
    aspect-ratio: 16 / 9;
    overflow: hidden;
}

.image-container img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Legacy: padding-bottom hack */
.image-container-legacy {
    position: relative;
    width: 100%;
    height: 0;
    padding-bottom: 56.25%;  /* 16:9 */
    overflow: hidden;
}

.image-container-legacy img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Common aspect ratios */
.aspect-video { aspect-ratio: 16 / 9; }
.aspect-square { aspect-ratio: 1 / 1; }
.aspect-portrait { aspect-ratio: 3 / 4; }
.aspect-wide { aspect-ratio: 21 / 9; }
.aspect-instagram { aspect-ratio: 4 / 5; }

/* Background images with aspect ratio */
.hero-bg {
    aspect-ratio: 16 / 9;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}

@media (max-width: 480px) {
    .hero-bg {
        aspect-ratio: 4 / 5;  /* Taller on mobile */
    }
}
</style>

Expected output: Images reserve their space before loading. The aspect-ratio CSS property prevents layout shift (CLS) as images load. Object-fit: cover ensures images fill the container without distortion.

Code Example: Background Images for Mobile

/* Mobile-first background images */
.hero {
    /* Mobile: smaller image loads first */
    background-image: url('hero-mobile.webp');
    background-size: cover;
    background-position: center;
    min-height: 60vh;
}

/* Tablet: larger image */
@media (min-width: 480px) {
    .hero {
        background-image: url('hero-tablet.webp');
        min-height: 50vh;
    }
}

/* Desktop: full-resolution image */
@media (min-width: 1024px) {
    .hero {
        background-image: url('hero-desktop.webp');
        min-height: 70vh;
    }
}

/* image-set() for pixel density */
.hero {
    background-image: image-set(
        url('hero.webp') 1x,
        url('hero-2x.webp') 2x,
        url('hero-3x.webp') 3x
    );
}

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

.lazy-bg.loaded {
    background-image: url('large-image.webp');
}
// Lazy loading background images
const lazyBgs = document.querySelectorAll('.lazy-bg');

const bgObserver = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            entry.target.classList.add('loaded');
            bgObserver.unobserve(entry.target);
        }
    });
}, {
    rootMargin: '200px'  // Start loading before visible
});

lazyBgs.forEach(bg => bgObserver.observe(bg));

Expected output: The hero background uses a small image on mobile and progressively larger images on wider screens. Non-critical background images are lazy loaded with Intersection Observer.

Common Mistakes

  1. No srcset attribute — The same large image is served to all devices, wasting bandwidth on mobile.
  2. No dimensions on images — Without width and height (or aspect-ratio), images cause Cumulative Layout Shift (CLS).
  3. Using max-width: 100% without height: auto — Images with only max-width: 100% can have incorrect intrinsic height.
  4. Not providing WebP fallback — Serve WebP with JPEG fallback via the picture element for broad browser support.
  5. Eager loading of all images — Only above-fold (LCP) images should load eagerly. Below-fold images use loading="lazy".
  6. Wrong image resolution for mobile — A 2400px image on a 375px screen wastes bandwidth. Serve appropriately sized images.
  7. No art direction — The same image crop on mobile and desktop often looks wrong. Use picture element for different crops.

Practice Questions

  1. What HTML attribute tells the browser which image to use at different viewport widths? The sizes attribute combined with srcset width descriptors (400w, 800w).
  2. How does the picture element support art direction? Multiple source elements with media queries allow different image crops for different viewports.
  3. What CSS property prevents layout shift from images? aspect-ratio (e.g., aspect-ratio: 16/9) or explicit width and height attributes.
  4. What loading attribute enables lazy loading for images? loading="lazy" on the img element.

FAQ

Should I use WebP or AVIF?

WebP has broader browser support (95%+). AVIF has better compression but less support (80%+). Serve both with picture element for maximum reach.

How many image sizes should I generate?

3-5 sizes: 400w (mobile), 800w (tablet), 1200w (small desktop), 1600w+ (large desktop). Automation tools handle this.

What is the best image format for photos?

WebP for broad compatibility. AVIF for best compression. JPEG as universal fallback. PNG only for images requiring transparency.

Mini Project

Build a responsive image gallery that implements all mobile-first image techniques. The gallery should: (1) use srcset with 4 width variants and sizes attribute, (2) use picture element for WebP/JPEG format switching, (3) use art direction (different crops for mobile portrait vs desktop landscape), (4) set explicit width/height on all img elements, (5) use aspect-ratio CSS to prevent CLS, (6) lazy load below-fold images, (7) use background-image with image-set() for a hero section, (8) lazy load non-critical background images. Test on a throttled 3G connection. Verify no CLS occurs and the correct image sizes load.

What's Next

Continue with Lesson 6: Mobile-First Forms to design forms for mobile users.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro