Home/Learn/HTML, CSS & Responsive/Responsive Images and Media

Responsive Images and Media

Intermediate
Responsive

Images are usually the largest thing on a page. srcset, modern formats and a reserved aspect ratio decide both how fast the page loads and whether it jumps while loading.

Overview

Sending a 2400px hero to a 360px phone wastes most of the bytes and much of the user's data allowance, and on a mid-range Android it delays the largest contentful paint by seconds. The browser can pick the right file for the screen if you describe the options with srcset and sizes, and it can pick a better format if you offer one with picture. Reserving the space with width, height or aspect-ratio then removes the layout shift that images otherwise cause. These three habits account for most image performance work.

srcset and sizes

Describe the options; let the browser choose based on screen and density.

srcset for files, sizes for layout
<!-- Density switching: same size, different resolutions -->
<img src="logo.png" srcset="logo.png 1x, logo@2x.png 2x" alt="AiCanCode">

<!-- Width switching: different sizes for different layouts -->
<img
  src="hero-800.jpg"
  srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1600.jpg 1600w"
  sizes="(min-width: 64rem) 50vw, 100vw"
  width="1600" height="900"
  alt="…">

<!-- srcset says how WIDE each file is.
     sizes says how wide the IMAGE will be at each breakpoint.
     The browser combines them with the device pixel ratio and picks.

     Omitting sizes makes the browser assume 100vw and download a
     file that is often twice as large as needed. -->

<!-- Format negotiation: AVIF, then WebP, then a fallback -->
<picture>
  <source type="image/avif" srcset="hero.avif">
  <source type="image/webp" srcset="hero.webp">
  <img src="hero.jpg" alt="…" width="1600" height="900">
</picture>

<!-- Art direction: a genuinely different crop on a phone -->
<picture>
  <source media="(max-width: 40rem)" srcset="hero-square.jpg">
  <img src="hero-wide.jpg" alt="…">
</picture>

Preventing Layout Shift

Reserve the space before the file arrives.

width + height, aspect-ratio, object-fit
/* Always set the intrinsic dimensions... */
<img src="cover.webp" width="640" height="360" alt="">

/* ...and let CSS scale it while keeping the ratio */
img { max-width: 100%; height: auto }

/* The browser derives the aspect ratio from the attributes and
   reserves the box immediately. Without them the page reflows when
   each image lands — the dominant cause of CLS. */

/* When the dimensions are not known ahead of time */
.thumb { aspect-ratio: 16 / 9; object-fit: cover }
.avatar { aspect-ratio: 1; object-fit: cover; border-radius: 50% }

/* object-fit decides how the image fills its box:
     cover    fill the box, crop the overflow   (usual choice)
     contain  fit entirely, letterboxed
     fill     stretch — distorts, avoid                        */
.hero img { object-fit: cover; object-position: center 30% }

/* Background images cannot be responsive with srcset. Use image-set,
   or an <img> with object-fit, which is usually better anyway
   because it supports alt text and lazy loading. */
background-image: image-set("bg.avif" type("image/avif"),
                            "bg.jpg" type("image/jpeg"));

Loading Priority

What loads first decides your LCP.

lazy below the fold, priority for the hero
<!-- Below the fold: defer it -->
<img loading="lazy" decoding="async" …>

<!-- The hero: the opposite. Never lazy-load the LCP element. -->
<img fetchpriority="high" …>
<link rel="preload" as="image" href="hero.avif" type="image/avif"
      fetchpriority="high">

<!-- Lazy-loading the hero is a common self-inflicted wound: the
     browser deprioritises the single image the metric is measuring. -->

/* Format sizes, for the same photo:
     JPEG  100%      WebP  ~70%      AVIF  ~50%
   Serve AVIF with a WebP fallback and the saving is immediate. */

/* Video on a phone */
<video preload="metadata" poster="thumb.jpg" playsinline muted>
/* preload="none" if it is unlikely to be played — an autoloading
   video can cost several megabytes before anyone presses play. */

/* Respect data saving */
@media (prefers-reduced-data: reduce) {
  .decorative-bg { background-image: none }
}

Key Points to Remember

  • 1srcset lists the available files and sizes describes the rendered width — omitting sizes makes the browser assume 100vw
  • 2picture with AVIF and WebP sources roughly halves image bytes with a JPEG fallback
  • 3width and height attributes let the browser reserve space and are the main defence against layout shift
  • 4aspect-ratio with object-fit: cover handles images whose dimensions are not known in advance
  • 5Never lazy-load the hero image — it is the LCP element and should be preloaded with high fetch priority

Interview Questions

Sign in to ask Aria
1

What is the difference between the srcset and sizes attributes?

Hard
2

How do image dimensions relate to Cumulative Layout Shift?

Medium
3

Why is loading="lazy" on a hero image harmful?

Medium

Ask Aria about Responsive Images and Media

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…