html-css-imagenes-flexibles-multimedia

Responsive Images in HTML and CSS

  • 6 min

A flexible image is a resource that adapts to its container without breaking the layout or becoming distorted.

When building a responsive website, text usually behaves quite well. Lines break, paragraphs shift down, and everything more or less finds its place.

Images and videos, on the other hand, have more personality. If an image is 1600px wide and the mobile screen is 390px, the browser won’t shrink it out of politeness unless we ask it to.

And then the classic responsive enemy appears: the horizontal scrollbar. That bottom bar that says something has overflowed to the right, and nobody knows exactly what.

Fluid Images

The first step is to ensure that images, videos, and iframes do not exceed the width of their container.

img,
video,
iframe {
  max-width: 100%;
  height: auto;
}
Copied!

With max-width: 100%, the element can be smaller than its original size if it doesn’t fit. With height: auto, it preserves its proportions and doesn’t get squashed.

<img src="paisaje.jpg" alt="Path through mountains at sunset">
Copied!

If the original image measures 1200px and the container measures 360px, the browser draws it at 360px wide, maintaining its aspect ratio. It doesn’t distort and doesn’t break the page.

This rule is often included in the base styles of a project. It’s small and very useful.

Reserving Space to Avoid Layout Shifts

A common issue is that the page loads the text first, and when the image arrives, everything jumps down. This is called layout shift, and it’s quite annoying.

To avoid this, it’s a good idea to specify dimensions or use aspect-ratio.

<img
  src="producto.jpg"
  alt="Reusable blue steel bottle"
  width="800"
  height="600"
>
Copied!

Even if CSS later adapts it, these attributes help the browser reserve the correct space before downloading the image.

We can also set a ratio from CSS.

.imagen-card {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}
Copied!

This way, the card maintains a stable height, even if the image takes a little while to appear.

Cropping with object-fit

Sometimes we don’t want the image to freely change its height. For example, in a card, we might need all photos to occupy an exact rectangle, even if each original image has different proportions.

If we set width and height without anything else, the image can become distorted.

.avatar {
  width: 200px;
  height: 200px;
}
Copied!

If the original photo is panoramic, the face might end up squashed. And nobody wants an avatar that looks like it went through a hydraulic press.

To solve this, we use object-fit.

.avatar {
  width: 200px;
  height: 200px;
  object-fit: cover;
  border-radius: 50%;
}
Copied!
  • fill: Fills the box, distorting if necessary. This is the default value.
  • contain: Shows the entire image without cropping, even if bands are left over.
  • cover: Fills the entire box, cropping the excess.
  • none: Does not scale the image.
  • scale-down: Uses the smaller result between none and contain.

In modern interfaces, you’ll use cover a lot, as it allows you to create clean and consistent thumbnails.

Controlling the Crop Point

object-fit: cover crops the image to fill the box. The crop is centered by default, but we can control the important point using object-position.

.foto-persona {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: center top;
}
Copied!

This is useful when we want to preserve a person’s face, the main product, or a specific area of a photograph.

.banner {
  width: 100%;
  height: 320px;
  object-fit: cover;
  object-position: 70% center;
}
Copied!

With this, we say that the important point is shifted somewhat to the right.

srcset: Images in Multiple Resolutions

What we’ve seen so far solves the visual problem. But we also need to talk about performance issues.

If we have a huge image for desktop, it doesn’t make sense for a mobile device to download that same image to display it at a small size.

For that, we have srcset, which allows us to offer several versions of the same image.

<img
  src="foto-800.jpg"
  srcset="
    foto-400.jpg 400w,
    foto-800.jpg 800w,
    foto-1600.jpg 1600w
  "
  sizes="(max-width: 600px) 100vw, 50vw"
  alt="Mountain landscape with a lake in the background"
>
Copied!

Each 400w, 800w or 1600w indicates the actual width of that file. The sizes attribute tells the browser what size the image will occupy in the layout.

Without sizes, the browser assumes by default that the image will occupy 100vw. Sometimes it guesses correctly, but if the image is in a column that takes up half the screen, it might download a larger version than necessary.

<picture> for Different Crops

srcset is for delivering the same image at different sizes. The <picture> tag is for when we want different images depending on the context.

For example, a panoramic photo might work great on a desktop, but on a mobile, it might leave the subject tiny in a corner.

<picture>
  <source
    media="(max-width: 799px)"
    srcset="montana-vertical.jpg"
  >
  <source
    media="(min-width: 800px)"
    srcset="montana-panoramica.jpg"
  >
  <img
    src="montana-panoramica.jpg"
    alt="Mountain trail with a person walking along the path"
  >
</picture>
Copied!

This is sometimes called directional art: we don’t just change the file size, we also change the framing so the image communicates well on every screen.

The final <img> inside <picture> is not optional. It’s the fallback content and also where we put the alt attribute. If you remove it, the structure is incomplete.

Responsive Videos and Iframes

Videos must also adapt. For a normal <video>, the same base rule helps a lot.

video {
  max-width: 100%;
  height: auto;
}
Copied!

For embedded videos using <iframe>, like YouTube, we can now use aspect-ratio.

.video-responsive {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
}
Copied!
<iframe
  class="video-responsive"
  src="https://www.youtube.com/embed/VIDEO_ID"
  title="Course video"
  allowfullscreen
></iframe>
Copied!

Previously, wrappers with padding-bottom were used. They worked, but were a bit more cumbersome. aspect-ratio lets us do it more cleanly.

Lazy Loading and Priority

Images can be heavy. If an image is far down, below the fold, there’s no need to download it immediately.

<img
  src="galeria-01.jpg"
  alt="Detail of a responsive mobile interface"
  loading="lazy"
>
Copied!

loading="lazy" tells the browser it can delay loading until the image is close to entering the viewport.

For the main image at the top of the page, on the other hand, we might want the opposite: to give it priority.

<img
  src="hero.jpg"
  alt="Webpage open on a laptop and a mobile phone"
  fetchpriority="high"
>
Copied!

Do not add loading="lazy" to the main image visible right when the page loads. If it’s the first thing the user needs to see, it’s best to load it quickly.