Images and videos are the heaviest and least flexible parts of most web pages. A photo is a fixed grid of pixels, and a video embed arrives with fixed width and height attributes. Drop either into a narrow phone layout without help, and it bursts out of its container and makes the whole page scroll sideways.
Making media responsive has two sides. The CSS side, which this lesson covers, makes images and videos display at the right size: shrinking to fit their container, keeping their shape, and cropping neatly when a design needs a fixed shape. The HTML side, covered in the HTML responsive images lesson, uses srcset, sizes and <picture> to download the right file for each screen, which matters a lot for speed.
You'll learn the famous one-line fix for fluid images, the modern aspect-ratio way to make video embeds responsive, how to handle background images on different screens with media queries and image-set(), and how to stop media from causing layout shifts while it loads.
The fluid image rule
img, picture, video, svg {
display: block;
max-width: 100%;
height: auto;
}max-width: 100%lets an image shrink to fit its container but never grow beyond its natural size, so small icons don't blow up and turn blurry.height: autokeeps the original proportions as the width changes. Without it, an image with aheightattribute gets squashed.display: blockremoves the small gap under images that appears because images are inline by default and sit on the text baseline.
Most CSS resets include this rule, and it fixes the majority of image overflow problems.
Responsive video and iframes
Native <video> elements behave like images, so max-width: 100%; height: auto works. Embeds such as YouTube or maps are <iframe> elements, which have no natural shape. The modern fix is aspect-ratio:
.embed { width: 100%; height: auto; aspect-ratio: 16 / 9; border: 0; }Older code uses the "padding hack": a wrapper with padding-top: 56.25% (9 divided by 16) and an absolutely positioned iframe inside. You'll still see it, but aspect-ratio is simpler and works in every modern browser.
Background images on every screen
| Need | CSS |
|---|---|
| Cover the whole box | background-size: cover; background-position: center; |
| Different crop on phones | Change background-position in a media query |
| Smaller file on phones | Change background-image in a media query, mobile first |
| Sharper on high-density screens | background-image: image-set("hero.webp" 1x, "hero@2x.webp" 2x); |
Background images are decoration: they have no alt text, so never put important content in them. For meaningful photos, use an <img> with object-fit: cover, which behaves like background-size: cover but stays accessible.
Preventing layout shift
When an image loads, the space it takes can jump from zero to its full height, pushing text down while someone is reading. Prevent it by:
- adding
widthandheightattributes to every<img>(CSSheight: autostill keeps it fluid; the browser uses the attributes to work out the shape); - giving embeds and placeholders an
aspect-ratio; - setting a background colour on image containers so the space is visible while loading.
Google measures this as Cumulative Layout Shift (CLS), one of the Core Web Vitals that affect search rankings.
CSS Responsive Images Syntax
Responsive media
img, video { display: block; max-width: 100%; height: auto; }
.embed { width: 100%; aspect-ratio: 16 / 9; border: 0; }
.hero { background: url(hero-small.jpg) center / cover; min-height: 50vh; }
@media (min-width: 900px) { .hero { background-image: url(hero-large.jpg); } }
.logo { background-image: image-set("logo.png" 1x, "logo@2x.png" 2x); }CSS Responsive Images Summary
img { max-width: 100%; height: auto; display: block; }makes images fluid.- Use
aspect-ratio: 16 / 9withwidth: 100%for responsive iframes and video embeds. background-size: coverfills a box; media queries andimage-set()swap background files.- Width and height attributes plus
aspect-ratioprevent layout shift. - Use HTML
srcsetand<picture>so phones download smaller files.
CSS Responsive Images Examples
Each example runs in the page. Edit the code and press Run to see what changes.
Fluid images
Narrow the result panel. The large photo shrinks, and the small icon stays at its natural size.
<div class="box">
<img src="https://picsum.photos/seed/canyon/1200/600" alt="Canyon at sunset" width="1200" height="600">
<img class="icon" src="https://picsum.photos/seed/icon/48/48" alt="Small icon" width="48" height="48">
</div>.box {
max-width: 420px;
padding: 10px;
border: 2px dashed #94a3b8;
}
img {
display: block;
max-width: 100%;
height: auto;
border-radius: 8px;
margin-bottom: 8px;
}Line-by-line explanation
- Line 2The container is narrower than the 1200px photo.
- Line 8No gap under images.
- Line 9The photo shrinks to fit, but the 48px icon doesn't stretch to fill.
- Line 10Proportions stay correct.
A responsive YouTube embed
<iframe class="embed"
src="https://www.youtube-nocookie.com/embed/UB1O30fR-EE"
title="HTML crash course video"
loading="lazy"
allowfullscreen></iframe>
<video class="clip" controls width="640" height="360" poster="https://picsum.photos/seed/poster/640/360">
<source src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4" type="video/mp4">
</video>.embed {
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
border: 0;
border-radius: 10px;
margin-bottom: 12px;
}
.clip {
display: block;
max-width: 100%;
height: auto;
border-radius: 10px;
}Line-by-line explanation
- Lines 2 to 4The embed fills the width and keeps a 16:9 shape at any size.
- Lines 11 to 13Native video works like an image.
A responsive background hero
Drag the panel wider than 700px to see the crop and layout change.
<section class="hero">
<h2>Weekend hikes</h2>
</section>.hero {
min-height: 220px;
display: grid;
place-items: end start;
padding: 16px;
border-radius: 12px;
color: white;
font-family: sans-serif;
background:
linear-gradient(transparent 40%, rgb(0 0 0 / 0.6)),
url("https://picsum.photos/seed/hike/800/1000") center top / cover;
}
@media (min-width: 700px) {
.hero {
min-height: 320px;
background-image:
linear-gradient(transparent 40%, rgb(0 0 0 / 0.6)),
url("https://picsum.photos/seed/hike/1600/700");
background-position: center;
}
}Line-by-line explanation
- Lines 9 to 11A gradient over the photo keeps the heading readable, and
coverfills the box. - Line 11Phones get a smaller, taller image cropped from the top.
- Lines 14 to 21Wide screens get a wider image file and a taller hero.
Common CSS Responsive Images Mistakes
width: 100% on every image
img { width: 100%; } /* small icons and logos stretch and blur */img { max-width: 100%; height: auto; }Forgetting height: auto
img { max-width: 100%; } /* with height="600" in the HTML, the image squashes */img { max-width: 100%; height: auto; }The old padding hack in new code
.wrap { position: relative; padding-top: 56.25%; }
.wrap iframe { position: absolute; inset: 0; width: 100%; height: 100%; }iframe { width: 100%; aspect-ratio: 16 / 9; }CSS Responsive Images in Real Projects
Responsive media in practice
News sites serve hero images through <picture> with different crops for phones and desktops, then style them with object-fit: cover. Video platforms' embed codes are made responsive with aspect-ratio. Image CDNs such as Cloudinary and Imgix create every size automatically, and frameworks like Next.js generate srcset for you. Retailers lazy-load product images further down long category pages to keep them fast.
CSS Responsive Images Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the fluid image rule.
img {
: 100%;
height: auto;
}
Why add height: auto to fluid images?
What's the modern way to make an iframe embed responsive?
Which function provides sharper background images on high-density screens?
The video embed should fill its container at 16:9 with no border, and the photo should shrink to fit without distorting. Fix the CSS.
<div class="col" style="width: 320px">
<iframe class="vid" src="about:blank" title="Video"></iframe>
<img class="pic" src="https://picsum.photos/seed/dbg/800/400" alt="Photo" width="800" height="400">
</div>.vid { width: 560px; height: 315px; }
.pic { width: 800px; }- Video fills the column
- Video is 16:9
- Photo fits and keeps its shape
CSS Responsive Images Quiz
5 questions to check what you learned.
Why does an image overflow on phones without CSS?
- Phones can't shrink images
- The alt text is too long
- It's a browser bug
- Images display at their natural pixel size by default
What does display: block fix on images?
- The small gap below the image caused by inline alignment
- Blurriness
- Slow loading
- Overflow
Why shouldn't important photos be CSS backgrounds?
- Backgrounds load slower
- Backgrounds can't be responsive
- They have no alt text, so screen readers miss them
- They can't be cropped
What does loading="lazy" do?
- Lowers image quality
- Shows a spinner
- Loads the image twice
- Delays downloading until the image is close to scrolling into view
Which Core Web Vital measures content jumping as images load?
- Largest Contentful Paint
- Cumulative Layout Shift
- Interaction to Next Paint
- Time to First Byte
CSS Responsive Images Challenge
Make a blog post's media responsive
- Make all
imgelementsdisplay: block,max-width: 100%andheight: auto - Make
.embedwidth: 100%withaspect-ratio: 16 / 9andborder: 0 - Give
.bannerbackground-size: coverandbackground-position: center
<article style="width: 300px">
<div class="banner" style="height: 120px; background-image: url(https://picsum.photos/seed/bn/900/300)"></div>
<img src="https://picsum.photos/seed/post/900/600" alt="Market stall" width="900" height="600">
<iframe class="embed" src="about:blank" title="Recipe video"></iframe>
</article>- Image fits and keeps its shape
- Embed is full width and 16:9
- Embed has no border
- Banner covers its box
height: auto for aspect-ratio to work.