34

I have several columns that I am giving equal width using flex. Each contains img tags, and I'd like those images to exhibit the object-fit: cover sizing.

.container {
  display: flex;
  flex-direction: row;
  width: 100%;
}
.test {
  flex: 1;
  margin-right: 1rem;
  overflow: hidden;
  height: 400px;
}
img {
  object-fit: cover;
}
<div class="container">
  <div class="test"><img src="http://placehold.it/1920x1080"></div>
  <div class="test"><img src="http://placehold.it/1920x1080"></div>
  <div class="test"><img src="http://placehold.it/1920x1080"></div>
  <div class="test"><img src="http://placehold.it/1920x1080"></div>
</div>

The images are not resizing, as can be seen in this demo. Why is that?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Jack Guy
  • 8,346
  • 8
  • 55
  • 86

6 Answers6

43

From the specification:

The object-fit property specifies how the contents of a replaced element should be fitted to the box established by its used height and width.

The key term being: fitted to the box established by its used height and width

The image gets replaced, not its container. And the box established by its used height and width relates to the image itself, not its container.

So, scrap the container and make the images themselves the flex items.

.container {
  display: flex;
  flex-direction: row;
  width: 100%;
}

img {
  object-fit: cover;
  flex: 1;
  margin-right: 1rem;
  overflow: hidden;
  height: 400px;
}
<div class="container">
  <img src="http://placehold.it/1920x1080">
  <img src="http://placehold.it/1920x1080">
  <img src="http://placehold.it/1920x1080">
  <img src="http://placehold.it/1920x1080">
</div>

Revised Codepen


Additional Details

5.5. Sizing Objects: the object-fit property

The object-fit property specifies how the contents of a replaced element should be fitted to the box established by its used height and width.

Here are three of the values:

  • cover

    The replaced content is sized to maintain its aspect ratio while filling the element's entire content box.

  • contain

    The replaced content is sized to maintain its aspect ratio while fitting within the element's content box.

  • fill

    The replaced content is sized to fill the element's content box.

With cover the image retains its aspect ratio and covers all available space. With this option, much of an image may be cropped off-screen.

With contain the aspect ratio is also maintained, but the image scales to fit within the box. This may result in whitespace on the left and/or right (portrait fit), or top and/or bottom (landscape fit). The object-position property can be used to shift the image within its box.

With fill the aspect ratio is abandoned and the image is sized to fit the box.


Browser Compatibility

As of this writing, object-fit is not supported by Internet Explorer. For a workaround see:

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
21

The problem is that object-fit specifies how an image is painted inside the img, but you didn't specify the sizes of these elements, only the sizes of their .test parents.

So an alternative to Michael_B's answer is making the images have the same size as the flex items:

img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

.container {
  display: flex;
  flex-direction: row;
  width: 100%;
}
.test {
  flex: 1;
  margin-right: 1rem;
  overflow: hidden;
  height: 400px;
}
img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}
<div class="container">
  <div class="test"><img src="http://placehold.it/1920x1080"></div>
  <div class="test"><img src="http://placehold.it/1920x1080"></div>
  <div class="test"><img src="http://placehold.it/1920x1080"></div>
  <div class="test"><img src="http://placehold.it/1920x1080"></div>
</div>
Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • 1
    I've been noticing for some time now that `object-fit` doesn't work by itself. In all cases I've seen, `height` and / or `width` must be specified in the same declaration. Nothing about this in the spec. Can `object-fit` work by itself? – Michael Benjamin May 10 '16 at 11:46
  • 2
    @Michael_B With only one size it still works, but it's usually useless. `object-fit` is basically useful when you have resized the `img` element without respecting the intrinsic aspect ratio. Then by default the image is distorted (fill), but you may want to maintain the aspect ratio in different ways (contain, cover). If you only set one size of the `img`, the other will be computed according to the aspect ratio. So all `object-fit` values will produce the same result. The exception is if you use advanced layout techniques like flexbox to modify the auto size after if has been resolved. – Oriol May 10 '16 at 12:00
  • Yes, that was the problem when I was testing `width:100%` on the `img` in the original code. It re-sized the image, but the `object-fit` property became useless. Thanks for the explanation. – Michael Benjamin May 10 '16 at 12:18
  • 2
    One more point that may be useful: I didn't consider `height: 100%` as a general solution on the nested image because if the container doesn't have a defined height, a percentage `height` wouldn't work, unless absolutely positioning. But it does work in this case because the container's height is defined. – Michael Benjamin May 10 '16 at 13:35
2

For anyone who can't just "scrap the container and make the images themselves the flex items," just add container levels:

<div class="display-flex">
  <div class="flex-grow position-relative">
    <div class="pos-absolute top-left-right-bottom-0">
      <img class="object-fit-cover height-width-100">
btown
  • 2,273
  • 3
  • 27
  • 38
0

As a way to support the object-fit functionality for your images in non-compatible browsers, you can create a CSS class with background-image and background-size. For it to properly calculate the occupied space, you wrap an img element and make it invisible. Example below.

HTML

<div class="my-image">
    <img src="path/to/my/image"/>
</div>

CSS

.my-image {
    background-image: url('path/to/my/image');
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
}

.my-image > img {
    visibility: hidden;
}
0

Using Bootstrap 5 you can do this with this kind of setup;

<div class="d-flex align-items-center justify-content-center text-center position-relative overflow-hidden vh-100">

  <!-- Put a higher z-index on this one -->
  <div class="container-fluid container-lg py-5 py-lg-10">
    <h1>Your content</h1>
  </div>

  <div class="position-absolute top-0 end-0 bottom-0 start-0">
    <img src="https://placehold.co/600x400" alt="" class="d-none d-lg-block w-100 h-100">
  </div>

</div>
-1

If the <img/> is stretched to 100% in IE11 then add flex-shrink: 0 on the <img/> itself, as adviced here: Flexbox on IE11: image stretched for no reason?

catamphetamine
  • 4,489
  • 30
  • 25