Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image flex item does not shrink height in a flexbox

I have a flex container which contains an img flex item.

I want this img to disregard its intrinsic height (90px) so that the height may shrink to match the sibling's flex item height (as per the default align-items: stretch style).

.container {
    border: 1px solid;
    display: flex;
}

.item {
    border: 1px solid;
}

.content {
    width: 200px;
    height: 50px;
    background-color: hotPink;
}
<div class="container">
    <img class="item" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ">
    <div class="item">
        <div class="content"></div>
    </div>
</div>

We can see the desired behaviour if we swap the img for a div:

.container {
    border: 1px solid;
    display: flex;
}

.item {
    border: 1px solid;
}

.dynamicHeightContent {
    width: 120px;
    height: 100%;
    background-color: green;
}

.content {
    width: 200px;
    height: 50px;
    background-color: hotPink;
}
<div class="container">
    <div class="item">
        <div class="dynamicHeightContent"></div>
    </div>
    <div class="item">
        <div class="content"></div>
    </div>
</div>

I have tried min-height: 0 on the img, to no avail.

  • What is the special behaviour that applies to img but not div?
  • How can we opt out of img's special behaviour so that it behaves like other flex items (such as div)? If there isn't a way to opt-out, is there a recommended workaround?

Note that whilst the img won't shrink its height, it does appear to grow:

.container {
    border: 1px solid;
    display: flex;
}

.item {
    border: 1px solid;
}

.content {
    width: 200px;
    height: 300px;
    background-color: hotPink;
}
<div class="container">
    <img class="item" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ">
    <div class="item">
        <div class="content"></div>
    </div>
</div>

Note: I'm happy to disregard the img's aspect ratio. I plan to avoid skewing the img via object-fit: cover.

like image 931
Oliver Joseph Ash Avatar asked Apr 11 '19 10:04

Oliver Joseph Ash


1 Answers

Note that in your example, the item is the flex item and not content - you should check the strech behaviour of item here.


How can we opt out of img's special behaviour so that it behaves like other flex items (such as div)?

It behaves like other flex items - <img> may not be very useful as a flex item but the stretch behaviour works fine:

  • if the image has more height than item, the item stretches to the height of the image
  • if the image has less height than item, the image stretches to the height of the content breaking its aspect ratio.

See demo below:

.container {
  border: 1px solid;
  display: flex;
}

.item {
  background: cadetblue;
}

.content {
  width: 200px;
  background-color: hotPink;
}

img {
  display: block;
}
<h2>Small content</h2>
<div class="container">
  <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ">
  <div class="item">
    <div class="content">some text here some text here some text here </div>
  </div>
</div>
<br/>
<h2>Large Content</h2>
<div class="container">
  <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ">
  <div class="item">
    <div class="content">some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here </div>
  </div>
</div>

I have tried min-height: 0 on the img, to no avail.

The min-height: 0 is given to a column flexbox along the flex direction to override the default auto behaviour (for row direction the property is min-width) - this doesn't work in the cross axis.

You can see details and some examples of this below:

  • Flexbox affects overflow-wrap behavior

  • Flexbox resize and scrollable overflow

  • Why don't flex items shrink past content size?

Wrapping image in a container

Now wrap the <img> in a div and see the same situation - the stretch behaviour is again good:

.container {
  border: 1px solid;
  display: flex;
}

.item {
  background: cadetblue;
}

.content {
  width: 200px;
  background-color: hotPink;
}

img {
  display: block;
}
<h2>Small content</h2>
<div class="container">
  <div class="item">
    <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ"></div>
  <div class="item">
    <div class="content">some text here some text here some text here </div>
  </div>
</div>
<br/>
<h2>Large Content</h2>
<div class="container">
  <div class="item">
    <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ"></div>
  <div class="item">
    <div class="content">some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here </div>
  </div>
</div>

The difference now is that you can use object-fit successfully on the image now (this does not work properlly if it is a flex item):

.container {
  border: 1px solid;
  display: flex;
}

.item {
  background: cadetblue;
}

.content {
  width: 200px;
  background-color: hotPink;
}

img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
<h2>Small content</h2>
<div class="container">
  <div class="item">
    <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ"></div>
  <div class="item">
    <div class="content">some text here some text here some text here </div>
  </div>
</div>
<br/>
<h2>Large Content</h2>
<div class="container">
  <div class="item">
    <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ"></div>
  <div class="item">
    <div class="content">some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here </div>
  </div>
</div>

I want this img to disregard its intrinsic height (90px) so that the height may shrink to match the sibling's flex item height

The only way to disregard the image height is to use positioning on the image wrapper:

  • position the image absolutely with respect to its wrapper,
  • you can either give a width to the image wrapper or give flex: 1 on item to get half of the available width horizontally.

See demo below:

.container {
  border: 1px solid;
  display: flex;
}

.item {
  background: cadetblue;
  flex: 1; /* equal width for items */
}

.content {
  width: 200px;
  background-color: hotPink;
}

.item:first-child { /* image container */
  position: relative;
}

img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  position: absolute; /* position absolutely */
  top: 0;
  left: 0;
}
<h2>Small content</h2>
<div class="container">
  <div class="item">
    <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ"></div>
  <div class="item">
    <div class="content">some text here some text here some text here </div>
  </div>
</div>
<br/>
<h2>Large Content</h2>
<div class="container">
  <div class="item">
    <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRu-3yBSd2b6JCOMcGVSOFf8X49QB3Ik-OI87gKEMwWLrdJxP5qOErmZQ"></div>
  <div class="item">
    <div class="content">some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here </div>
  </div>
</div>
like image 182
kukkuz Avatar answered Oct 04 '22 16:10

kukkuz