albert.walickihire me
← all solutions
css

How to fit an image into its container?

Make an image fit its container with max-width, fill a box of a fixed size with object-fit cover or contain, and load the right file size with srcset.

For most images this rule is enough. The image never gets wider than its container, and it keeps its proportions:

img {
  display: block;
  max-width: 100%;
  height: auto;
}

display: block removes the small gap below the image that appears because images are inline by default (more in extra space below image). Leave that line out for images that sit inside a line of text. Most CSS resets include this rule.

Fill a box with a fixed size

When the box has its own size, like a thumbnail, a card header or a hero, give the image the full size of the box and pick an object-fit value:

<div class="thumb">
  <img src="/photos/lake.jpg" alt="A lake at sunrise">
</div>
.thumb {
  width: 300px;
  height: 200px;
}

.thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
  • object-fit: cover fills the whole box and crops the parts that don't fit. Use it for photos.
  • object-fit: contain shows the whole image and leaves empty space on two sides. Use it for logos and product shots that must not be cropped.
  • The default, fill, stretches the image to the box and distorts it.
.logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

The empty space around a contain image is transparent, so the parent's background shows through.

object-position moves the image inside the box. It defaults to center. Use top so faces in portraits don't get cropped, or percentages for exact control:

.team-photo img {
  object-fit: cover;
  object-position: 50% 20%;
}

The parent needs a height

height: 100% only works when the parent has a definite height. If the parent's height comes from its content, the percentage behaves like auto, and the image shows at its natural height and spills out of the box. Give the parent a height, an aspect-ratio, or a height from a flex or grid layout.

Often it's simpler to skip the wrapper and put the ratio on the image itself:

.card img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

More on ratios in how to keep the aspect ratio of an image.

Load the right file size with srcset

CSS only changes how big the image looks. A 3000px photo squeezed into a 300px card still downloads all 3000 pixels. srcset lists the files you have and their widths, and sizes tells the browser how wide the image will be on the page, so it can pick the smallest file that still looks sharp:

<img
  src="/photos/lake-800.jpg"
  srcset="
    /photos/lake-400.jpg 400w,
    /photos/lake-800.jpg 800w,
    /photos/lake-1600.jpg 1600w
  "
  sizes="(min-width: 1024px) 33vw, 100vw"
  width="1600"
  height="1067"
  alt="A lake at sunrise"
>

This sizes says: on screens 1024px and wider the image takes a third of the viewport width, otherwise the full width. The browser also takes pixel density into account, so a phone with a high-density screen may still pick the 1600px file. If you use Next.js, the next/image component generates srcset for you.

Background images

For decorative images set in CSS, background-size does the job of object-fit:

.hero {
  min-height: 60vh;
  background-image: url('/photos/lake.jpg');
  background-size: cover;
  background-position: center;
}

background-size: contain together with background-repeat: no-repeat shows the whole image. A background doesn't give the element any size, so the element needs a height or content of its own.

I use <img> with object-fit: cover for almost everything and keep backgrounds for decoration. An <img> has alt text, supports srcset, and the browser finds it straight in the HTML, sooner than a CSS background.

more solutions
work with me

Got something that needs building?

Frontend builds, full-stack features in Django, design-system work. Available for work.

See my workGet in touch