# Responsive Images: max-width, object-fit and srcset

Make pictures fit any screen with max-width, aspect-ratio and object-fit in CSS, and send each screen a picture of the right size and crop with srcset, sizes, picture and lazy loading in the HTML.

Journeyman · CSS · Web Development · Updated November 1, 2026

## After this lesson you can

- Make a picture fill its box with max-width, aspect-ratio, object-fit and object-position
- Use srcset, sizes, a picture element and lazy loading so each screen downloads the right picture when it's needed
- Choose the right tool for a responsive problem, from the viewport line and media queries to object-fit and srcset

## Key takeaways

- max-width 100% with height auto keeps a picture inside its box and in proportion.
- aspect-ratio gives a box a shape, object-fit cover fills it by cropping the picture, and object-position chooses which part stays in view.
- srcset lists the same picture at several widths, and sizes tells the browser how wide it shows, so a phone downloads a smaller file.
- A picture element swaps in a different crop of the photo at a breakpoint. Its img is required and holds the alt text.
- loading="lazy" waits to download a picture until the reader scrolls near it. Never use it on the first picture on the page.

Photos are usually the biggest part of a page, and they cause most of its phone problems: a picture that pokes out past the edge of the screen, a photo squashed out of shape, a phone on a slow connection downloading a picture big enough for a cinema screen. Every site you'll build has pictures: product photos in a shop, a hero photo on a landing page, team photos on an "About us" page. This lesson makes them fit, look right and load fast. It's CSS first, then the HTML attributes that go with it, taught here from the start.

## Pictures that stay inside their box

A picture shows at its own size unless something stops it. Sol Taco Truck's photo is 1600 pixels wide, so on a phone it pushes the page sideways. One rule, usually written for every picture on the site, fixes it:

```css
img {
  max-width: 100%;
  height: auto;
}
```

`max-width: 100%` means "never wider than the box I'm in": a big photo shrinks to fit, and a small one keeps its own size. `height: auto` lets the height follow the width, so the shrunk photo keeps its proportions instead of being squashed.

Give each `<img>` its real `width` and `height` attributes in the HTML too, such as `width="1600" height="1067"`. The browser uses them to save the right amount of space while the picture downloads, so the text under it doesn't jump down when it arrives. With the rule above, the picture still shrinks to fit.

## A box of the right shape: aspect-ratio and object-fit

Think of a picture frame and a photo print. When the print's shape doesn't match the frame, you either trim the print so it fills the frame, or you leave a border around it.

On the taco truck's page, the photo should be a wide strip on a phone, 16 by 9, whatever shape the photo file is. Two properties do it:

```css
.truck-photo {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: center 70%;
}
```

- **`aspect-ratio: 16 / 9`** (read "16 by 9", or "16 to 9") gives the box its shape: for every 16 parts of width, 9 of height. An **aspect ratio** is the proportion of width to height. `1 / 1` is a square, and `4 / 3` an old TV.
- **`object-fit: cover`** fills the box with the picture, keeping its proportions and trimming whatever doesn't fit, like trimming the print. `object-fit: contain` shows the whole picture inside the box, with empty space around it, like the border. The default, `fill`, stretches the picture to the box and distorts it.
- **`object-position: center 70%`** chooses which part stays in view when `cover` trims: across, the middle; down, 70% of the way toward the bottom, where the truck's serving window is. Keywords work too: `center bottom`, `left top`.

![The same photo of the taco truck in a wide 16 by 9 box three ways: with fill, stretched and distorted; with contain, the whole photo shown with empty bands at the sides; with cover, the box filled and the sky trimmed off the top](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/10/d23246a48e9144a1864ad55957b41f47.webp)

**Try it.** Put any photo on a page with the `.truck-photo` rule, and change `aspect-ratio` to `1 / 1`, then `4 / 3`. Then try `object-fit: contain` and `fill`, and move `object-position` from `center top` to `center bottom` to see which part of the photo stays.

## The right file for each screen: srcset and sizes

A phone showing a photo 390 pixels wide doesn't need a file 1920 pixels wide. That's several times the download, on a phone connection, for nothing. The HTML can offer the same photo in several sizes and let the browser choose. That's what makes it a **responsive image**:

```html
<img src="images/truck-1280.jpg"
     srcset="images/truck-640.jpg 640w,
             images/truck-1280.jpg 1280w,
             images/truck-1920.jpg 1920w"
     sizes="(min-width: 64rem) 50vw, 100vw"
     alt="The Sol Taco Truck, painted sunset orange, parked under the trees by the river"
     width="1920" height="1280">
```

- **`srcset`** (read "source set") lists the files, separated by commas. After each one, its real width: `640w` is read "640 w", and means "this file is 640 pixels wide".
- **`sizes`** tells the browser how wide the picture will show, because it decides before the CSS has loaded. Read this one as: "on a screen at least 64rem wide, the picture is half the window (`50vw`); otherwise, it's the whole width (`100vw`)". It uses the same media conditions as a media query.
- **`src`** is the file for browsers too old to understand `srcset`. It's usually one of the srcset files, here the 1280 one.

The browser does the math. A phone 390 pixels wide with a sharp screen (3 dots for every CSS pixel) needs about 1170 pixels, so it takes the 1280 file; an older phone with a 2x screen needs 780 and also takes 1280; a small, plain screen takes the 640. You list the files, and the browser chooses for each screen.

For a picture that always shows at the same size, such as a logo, there's a shorter form, with `x` for screen sharpness: `srcset="images/logo.png 1x, images/logo-2x.png 2x"`.

## A different crop on a phone: the picture element

Sometimes a phone needs a different photo, not a smaller one. On a wide screen, the whole truck under the trees by the river looks great. On a phone, the truck becomes a tiny orange speck. Better to show a close-up of the serving window. The `<picture>` element swaps in a different file at a breakpoint:

```html
<picture>
  <source media="(min-width: 40rem)" srcset="images/truck-wide.jpg">
  <img src="images/truck-window.jpg" alt="The Sol Taco Truck's serving window, with the menu board beside it" width="800" height="1000">
</picture>
```

The browser reads the `<source>` lines from the top and uses the first one whose `media` is true. If none is, it uses the `<img>`. So the `<img>` is the phone's photo, and it's required: without it, nothing shows. The `alt` text and your CSS go on the `<img>`, the same as for any picture. Choosing a different crop for each screen is called *art direction*.

## Lazy loading: pictures further down can wait

The taco truck's page ends with photos of the food: the elote, the horchata, the al pastor tacos. Someone checking the hours may never scroll that far, so why download them right away?

```html
<img src="images/elote.jpg" alt="Grilled corn on the cob with lime and chili" width="800" height="600" loading="lazy">
```

`loading="lazy"` tells the browser to wait until the reader scrolls close to the picture before downloading it. The page opens faster, especially on a phone. Two rules go with it:

- **Never lazy-load the first picture people see**, such as the truck's photo at the top. It should start downloading right away.
- **Keep the `width` and `height` attributes**, so the browser saves the right space before the picture arrives.

## Which tool, when

This chapter has given you a toolbox. Here's which tool fixes which problem:

| The problem | The tool |
|---|---|
| The whole page is tiny on a phone | The viewport line in the `<head>` |
| A box is wider than a phone's screen | `max-width` instead of `width` |
| A picture pokes out past the screen | `max-width: 100%` and `height: auto` |
| The layout should change when there's more room | A `min-width` media query, at the width where the content breaks |
| Dark colors for readers who chose a dark theme | `@media (prefers-color-scheme: dark)` |
| Photos of different shapes should fill same-shaped boxes | `aspect-ratio` and `object-fit: cover` |
| Phones download a picture far bigger than they show | `srcset` and `sizes` |
| A phone needs a different crop of the photo | `<picture>` with a `<source>` |
| Pictures far down the page slow down the first view | `loading="lazy"` |

## Check yourself

2 questions to try on the lesson page.

## So what

The CSS makes a picture fit its box and look right; the HTML makes sure each screen downloads only the picture it needs. Together they give you a page that looks good and opens fast on the phone of someone who's hungry right now.

## Key terms

- [Responsive image](https://www.ask-codey.com/glossary/responsive-image)
- [srcset](https://www.ask-codey.com/glossary/srcset)
- [sizes](https://www.ask-codey.com/glossary/sizes)
- [&lt;picture>](https://www.ask-codey.com/glossary/picture)
- [object-fit](https://www.ask-codey.com/glossary/object-fit)
- [Aspect ratio](https://www.ask-codey.com/glossary/aspect-ratio)

## Cheat sheets

- [Responsive Images: max-width, object-fit and srcset](https://www.ask-codey.com/cheat-sheets/css-responsive-images-cheat-sheet)

## Related

- [Responsive Design and the Viewport](https://www.ask-codey.com/lessons/css-responsive-design-and-viewport)
- [Mobile First: Start Small, Then Add Room](https://www.ask-codey.com/lessons/css-mobile-first)

Source: https://www.ask-codey.com/lessons/css-responsive-images
