Responsive Images in HTML
Your page will be seen on a tiny phone held in one hand, on a tablet on a kitchen table, on a laptop, on a huge monitor in an office, and on a television across a room. The screens differ in size by a factor of ten, in sharpness by a factor of three, and the internet connections feeding them differ even more.
If you serve the same single image to all of them, somebody loses. The phone downloads far more than it can show. The big monitor gets a blurry, stretched picture. Responsive images are the set of tools HTML and CSS give you so that every visitor gets an image that fits their screen, looks sharp, and does not waste their data. This lesson is the map. The next lessons walk each road in detail.
What You Will Learnβ
- Why one image file cannot suit every device
- The difference between CSS pixels and device pixels
- The three problems responsive images solve
- How to make images flexible with CSS, and build a fluid gallery
- A first look at
srcset,sizes, and<picture> - How to check which file the browser actually chose
- A simple plan for choosing the right technique
Why One File Is Not Enoughβ
Picture a 2400-pixel-wide photograph, sized for a large desktop.
| Visitor | What goes wrong with the single big file |
|---|---|
| A phone on a slow network | Downloads about 1 MB when a 100 KB version would look the same on a small screen |
| A tablet | Wastes data, and decodes a huge image for a small display |
| A very large, sharp monitor | Might actually need that size, and a smaller file would look soft |
| Someone on a limited data plan | Pays for pixels they can never see |
Now imagine the opposite: a 400-pixel image for everyone. It loads quickly, but it looks blurry on large and sharp screens. Neither extreme is good for everyone. The answer is to offer a choice and let the browser pick.
A Short Lesson in Pixelsβ
To understand responsive images, you need to know two kinds of pixels.
| Kind | What it is |
|---|---|
| CSS pixel | The unit you write in HTML and CSS, such as width="300". It is a logical unit |
| Device pixel | A physical dot on the screen |
On older screens, one CSS pixel was one device pixel. On modern high-density screens, one CSS pixel is covered by two, three, or even more device pixels. The ratio is called the device pixel ratio (DPR).
| Screen | Typical DPR | A 300 CSS-pixel-wide image needs about... |
|---|---|---|
| Older or budget monitors | 1 | 300 pixels of image data |
| Many laptops and phones | 2 | 600 pixels |
| Some high-end phones | 3 | 900 pixels |
This is why a photo that looks crisp on one device can look soft on another, and why "just make everything big" and "just make everything small" both fail.
Three Problems, Three Toolsβ
Responsive images solve three different problems. Knowing which one you have tells you which tool to use.
| Problem | What you need | Tool | Lesson |
|---|---|---|---|
| 1. The image should fit its space | A flexible image that never overflows | CSS: max-width, width, aspect-ratio, object-fit | This lesson |
| 2. The right size for each device | The same picture in several sizes, so each device downloads what it needs | srcset and sizes on <img> | Srcset and Sizes |
| 3. The right picture for each situation | A different crop, shape, or file format | The <picture> element | Picture Element |
The first problem is about layout. The second is about resolution (called resolution switching). The third is about content (called art direction) or format. Many pages need all three.
Tool 1: Flexible Images With CSSβ
You met these rules in The img Element and Width and Height.
img {
max-width: 100%;
height: auto;
}
With them, an image never overflows its container, keeps its shape, and shrinks smoothly as the window narrows. Put the real width and height in the HTML, so the browser reserves the right space.
A Fluid Gallery With CSS Gridβ
For a set of pictures, CSS Grid can adjust the number of columns to the available space with no media queries at all.
- HTML + CSS
- Browser Output
<style>
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 0.75rem;
}
.gallery img {
width: 100%;
aspect-ratio: 3 / 2;
object-fit: cover;
display: block;
}
</style>
<div class="gallery">
<img src="images/a.jpg" alt="Sailboat at sunrise" width="600" height="400" />
<img src="images/b.jpg" alt="Fishing nets drying on a pier" width="600" height="400" />
<img src="images/c.jpg" alt="A lighthouse at dusk" width="600" height="400" />
<img src="images/d.jpg" alt="Waves breaking on rocks" width="600" height="400" />
</div>
Resize the window and the grid reflows: four columns on a wide screen, two or one on a narrow one. The aspect-ratio and object-fit: cover keep every tile the same shape.
Tool 2: A Taste of srcset and sizesβ
Flexible CSS fixes layout, but the browser still downloads one file. To let each device download a different size, you give the browser a menu.
<img
src="images/harbor-800.jpg"
srcset="
images/harbor-400.jpg 400w,
images/harbor-800.jpg 800w,
images/harbor-1600.jpg 1600w
"
sizes="(min-width: 60rem) 50vw, 100vw"
alt="Fishing boats resting in a calm harbor at sunrise"
width="1600"
height="1067"
/>
In plain words:
srcsetlists the available files, with each file's real width in pixels (thewnumber).sizestells the browser how wide the image will be on screen: half the window on wide screens, the full window otherwise.- The browser knows its own screen size, pixel density, and often its network conditions. It picks the best file from the menu.
srcis the fallback for browsers that do not understandsrcset.
You do not choose the file. You describe the options, and the browser decides. The details come in Srcset and Sizes.
Tool 3: A Taste of <picture>β
Sometimes you do not want the browser to choose a size. You want to choose which picture or which format.
Art Direction: Different Cropsβ
A wide landscape photo works on a desktop. On a narrow phone screen, the same photo shrinks until the main subject is tiny. A tighter crop would work much better.
<picture>
<source media="(max-width: 40rem)" srcset="images/harbor-crop-square.jpg" />
<img
src="images/harbor-wide.jpg"
alt="Fishing boats resting in a calm harbor at sunrise"
width="1600"
height="900"
/>
</picture>
Format Switchingβ
<picture>
<source srcset="images/harbor.avif" type="image/avif" />
<source srcset="images/harbor.webp" type="image/webp" />
<img src="images/harbor.jpg" alt="Fishing boats at sunrise" width="1200" height="800" />
</picture>
You will practice both in Picture Element.
Comparing the Threeβ
| CSS only | srcset and sizes | <picture> | |
|---|---|---|---|
| Who decides which file loads? | You (one file) | The browser | You set rules, the browser follows the first match |
| Solves | Fitting the layout | Right size for each screen and density | Right crop or right format |
| Same picture? | Yes | Yes, in several sizes | Can be different pictures |
| Extra files needed? | No | Yes, several sizes | Yes, several crops or formats |
| Complexity | Low | Medium | Medium to high |
Mobile First: A Good Habitβ
Build for the smallest screen first, then enhance for bigger ones. For images, this means:
- Start with a small, light default in
src. A visitor on a weak connection still gets something good, fast. - Offer larger versions through
srcsetfor screens that can use them. - Use
<picture>only where a different crop or format is really worth the extra work.
This way, nobody downloads more than they need, and the worst-case experience is still a good one.
What About CSS Background Images?β
Background images defined in CSS can also be responsive. They do not have alt text, so keep them for decoration only.
.hero {
background-image: url("images/hero-800.jpg");
background-size: cover;
background-position: center;
}
@media (min-width: 60rem) {
.hero { background-image: url("images/hero-1600.jpg"); }
}
/* Different files for different pixel densities */
@media (min-resolution: 2dppx) {
.hero { background-image: url("images/hero-1600.jpg"); }
}
Content images that carry meaning should stay in <img>, where alt, srcset, and <picture> are available.
How to See What the Browser Choseβ
With srcset and <picture>, the browser picks a file. You can find out which one.
In the Browser Toolsβ
- Open your page and open the developer tools.
- Go to the Network tab and filter by Img.
- Reload the page and note which files were downloaded.
- Use the device toolbar to pretend to be a phone, change the screen size, and set a slow connection. Reload again and compare.
With JavaScriptβ
const pictures = document.querySelectorAll("img");
pictures.forEach((img) => {
console.log(img.alt, "β", img.currentSrc, `(${img.naturalWidth} px wide)`);
});
currentSrc is the file the browser is using right now. naturalWidth is that file's real width in pixels.
Test on a real phone as well as in the device toolbar, on mobile data, if you can. Pay attention to how fast the first screen appears, and whether images look sharp.
A Simple Planβ
Use this checklist the next time you add an image.
- Is it decoration? Consider a CSS background, or
alt="". - Set
widthandheight, and usemax-width: 100%; height: auto;. - Resize and compress a sensible set of sizes, such as 400, 800, and 1600 pixels wide.
- Add
srcsetandsizesso each device can pick its size. - Do the crops differ on small screens? Use
<picture>withmedia. - Do you want modern formats? Use
<picture>withtypeand a JPEG fallback. - Is the image far down the page? Add
loading="lazy". - Test on a small and a large screen.
Responsive Images and Global Audiencesβ
Responsive images matter most to people with the fewest resources.
- Data is expensive in many regions. A well-sized image can cost a tenth as much as an oversized one.
- Networks vary widely, even within a city. Light defaults make your page usable on weak connections.
- Devices vary widely. A budget phone struggles to decode a giant image.
- Do not put text inside images, since a scaled-down image can make the text unreadable. Keep words in HTML, where they adapt to the screen and can be translated.
Common Mistakesβ
Mistake 1: One huge file for everyoneβ
It wastes data and slows pages. Offer several sizes.
Mistake 2: Forgetting max-width: 100%β
Large images overflow narrow screens and force sideways scrolling.
Mistake 3: srcset without sizesβ
Without sizes, the browser assumes the image fills the whole window, and may download too large a file. You will learn the right way in the next lesson.
Mistake 4: Using <picture> when srcset is enoughβ
If you only need different sizes of the same picture, srcset is simpler and lets the browser decide.
Mistake 5: Not testingβ
What you see on a fast laptop is not what visitors see on a slow phone.
Mistake 6: Hiding images with CSS instead of not loading themβ
display: none on an image may still download it. Use <picture> or lazy loading to avoid unneeded downloads.
Mistake 7: Missing alt text on the inner <img>β
In a <picture>, only the <img> carries alt, width, and height. Never leave them out.
Try It Yourselfβ
Here is a short project.
- Choose one photo and export it at 400, 800, and 1600 pixels wide.
- Add the 800-pixel version with
width,height, andalt, and the standard CSS rules. - Build the fluid gallery with CSS Grid, using four pictures, and resize your window.
- Add the
srcsetpreview from this lesson to one image, and open the Network tab to see which file is chosen at different window sizes. - Change the device toolbar to a phone and reload. Which file loads now?
- Log
currentSrcandnaturalWidthfor each image with the JavaScript snippet. - Make a tighter crop of your photo and use
<picture>with amediacondition so phones receive it. - Write one sentence for each image on your page: which of the three problems does it solve?
Quick Recapβ
Click a question to check your answer.
1. Why can't one image file suit every device?
Screens differ in size, pixel density, and network speed. A large file wastes data on small screens, and a small file looks blurry on large, sharp ones.
2. What is the difference between a CSS pixel and a device pixel?
A CSS pixel is a logical unit used in code. A device pixel is a physical dot on the screen. On high-density screens, one CSS pixel can cover several device pixels.
3. Which tool solves "right size for each device"?
srcset with sizes, which lets the browser choose from several sizes of the same image.
4. When do you need <picture> instead of srcset?
When you want a different crop for different screens (art direction), or you want to offer different file formats with fallbacks.
5. How can you tell which file the browser actually loaded?
Look at the Network tab in developer tools, or read the image's currentSrc in JavaScript.
Key Takeawaysβ
- Responsive images give every visitor an image that fits their screen, looks sharp, and does not waste data.
- CSS makes images flexible.
srcsetandsizesoffer the right size.<picture>offers the right crop or format. - High-density screens need more pixels in the file than the CSS size suggests.
- Think mobile first: a light default, with larger files for screens that can use them.
- Always test with developer tools and on real devices.
Now you can see the whole picture. Next, learn how to give the browser a menu of sizes in Srcset and Sizes.