2

I am trying to make a flexbox grid of items, where each row will stretch to be the same height as the tallest item.

However, no matter what I seem to try either the content of the largest item is pushed outside and overflows, or the other items do not stretch.

I have tried a single box that will be display:flex and the flex item of the main container. And putting it inside a wrapper. So the wrapper is the flex item and the box inside the wrapper is display:flex

Below is a Codepen of what I am trying to do. It's a 50/50 ratio of bottom image to the top text area.

.flex-container {
  display: flex;
  max-width: 500px;
  flex-flow: row wrap;
  height: auto;
  align-items: stretch;
}

.flex-item {
  width: 100px;
  margin: 30px;
}

.item {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.upper {
  order: 1;
  flex: 0 0 50%;
  border: 1px solid red;
}

.lower {
  order: 2;
  flex: 0 0 50%;
  border: 1px solid blue;
  display: flex;
}

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

.flex-item2 {
  width: 100px;
  margin: 30px;
  display: flex;
  flex-direction: column;
}
<h1>Attempt 1</h1>
<div class="flex-container">
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
        <p>hello</p>
        <p>hello</p>
        <p>hello</p>
        <p>hello</p>
        <p>hello</p>
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
        <p>hello</p>
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
        <p>hello</p>
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>
  <div class="flex-item">
    <div class="item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
    </div>
  </div>

</div>

<h1>Attempt 2</h1>
<div class="flex-container">
  <div class="flex-item2">
    <div class="upper">
      <p>hello</p>
    </div>
    <div class="lower">
      <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
    </div>
  </div>
  <div class="flex-item2">
    <div class="upper">
      <p>hello</p>
    </div>
    <div class="lower">
      <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
    </div>
  </div>
  <div class="flex-item2">
    <div class="upper">
      <p>hello</p>
      <p>hello</p>
      <p>hello</p>
      <p>hello</p>
      <p>hello</p>
      <p>hello</p>
    </div>
    <div class="lower">
      <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
    </div>
  </div>
  <div class="flex-item2">
    <div class="upper">
      <p>hello</p>
    </div>
    <div class="lower">
      <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
    </div>
  </div>
  <div class="flex-item2">
    <div class="upper">
      <p>hello</p>
      <p>hello</p>
      <p>hello</p>
      <p>hello</p>
      <p>hello</p>
    </div>
    <div class="lower">
      <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
    </div>
  </div>
  <div class="flex-item2">
    <div class="upper">
      <p>hello</p>
    </div>
    <div class="lower">
      <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
    </div>
  </div>
  <div class="flex-item2">
    <div class="upper">
      <p>hello</p>
    </div>
    <div class="lower">
      <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
    </div>
  </div>
  <div class="flex-item2">
    <div class="upper">
      <p>hello</p>
    </div>
    <div class="lower">
      <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
    </div>
  </div>



</div>

Full Pen

https://codepen.io/Richardadsmith/pen/GRRPQLy?editors=1100

THess
  • 1,003
  • 1
  • 13
  • 21

3 Answers3

3

I think you've stumbled upon an interesting problem with flex layout. And you've phrased it exactly right (to paraphrase):

"What are the limits of align-items: stretch?"

Based on your example, there appear to be some limits:

Here's where I am so far, based on experimentation with Chrome:

  1. According to the flexbox spec:

    In a multi-line flex container, the cross size of each line is the minimum size necessary to contain the flex items on the line.

    Therefore, in your layout, which is set to flex-wrap: wrap (making it multi-line), your requirement:

    "I am trying to make a flexbox grid of items, where each row will stretch to be the same height as the tallest item."

    … should be met.

    But it isn't.

    As you pointed out:

    "... no matter what I seem to try either the content of the largest item is pushed outside and overflows, or the other items do not stretch."


  1. I think the reason the items in each row don't stretch to the height of the tallest item in that row has to do with another flex function: align-content: stretch.

    This function forces the flex container to create flex lines of equal height, limiting the growth of flex items in each row.

    But changing the value of align-content, and setting heights and min-heights on the container, don't alter the behavior. Seems like a pretty clear align-items limitation to me.


  1. You may not be able to achieve flex items that stretch to the height of the tallest item in the row in a multi-line container (it's certainly possible in a single line container), but you can get them all to be equal height, which I understand is something that may not work for you.

    Here are a few ideas that may move you closer to an overall solution:

    • Method #1: Remove width: 100px from the image elements (demo). Obviously, this isn't a useful solution, as it allows the images to expand to their natural width. It's just meant to identify a problem area. Also, it illustrates items overlapping rows (flex lines), which supports the theory of align-content serving as a constraint on align-items.

    • Method #2: Enable flex-shrink on the image containers. So instead of .lower { flex: 0 0 50% } use flex: 0 1 50%. This allows the container to fit within the row / flex line (demo).

    • Method #3: Add overflow: auto to the flex items (demo). Again, probably not useful, but establishes equal height rows.


Lastly, maybe I missed something entirely here, which would be good news, since it would be nice to know that flex items can stretch to the height of the tallest item in each row, as defined in the spec. Good luck.

More info:

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    Brilliant response. I think we have both come to the same conclusion. The items can stretch, row by row to fit the tallest in the row, but there seem to be limits in the way this is calculated. When I try and force a 50/50 ratio between the upper and lower halves the content of the flex-item overflows out the bottom. This does not seem to be an issue if the items in the entire container are roughly the same size, but when there is great variation it caused trouble My solution was to drop the 50/50 ratio allow the image at the bottom to shrink down, while keeping the image ratio intact. – theHappyDev Nov 18 '19 at 19:17
  • Right. There may also be a rendering order issue at play here. For example, by the time the browser gets to rendering the content in the items, it has already laid out the flex lines, forcing the content to exist in this inflexible space. – Michael Benjamin Nov 18 '19 at 19:28
  • Yeah, that's my current working theory. It's a shame, but I guess we can't have everything – theHappyDev Nov 18 '19 at 19:35
  • It is a shame. Even with a `min-height` on the container the lines don't expand. Oh well. Maybe somebody else will chime in. @TemaniAfif is good at pinpointing the source of these sorts of problems. – Michael Benjamin Nov 18 '19 at 19:46
  • 1
    Hmmm... Very interesting! Seems like it has to do with the height of the containers also. In order to have fixed height for the container seems like you need a value. I did some test and I come up with an pretty interesting result [here](https://jsfiddle.net/qucmpv42/) . This is still not what you want, but maybe this will help other too. – Berci Nov 18 '19 at 22:21
0

The first attempt is good except the height:100%; . Flex containers don't work well with height 100%. You can read more about this here and here

Berci
  • 2,876
  • 1
  • 18
  • 28
  • Thanks for replying, when trying without the height 100% the items still stretch in an odd way. Please see attempt 2 in the codepen. – theHappyDev Nov 18 '19 at 13:20
  • Is because you give the image `width:100%; height:100%` so the image is trying to fit in, but is doesn't have space (because of the aspect ratio) so it will work weird. Is kind of hard to accomplish what you want because you have no actual heights. But the image itself has a with and a height. So if you put everything relative will be relative to the image. If you don't, your image will act weird. You can see the ideea of relative to the image [here](https://codepen.io/Richardadsmith/pen/GRRPQLy?editors=1100). I know is not what you want, but to make an ideea of what I am saying. – Berci Nov 18 '19 at 15:58
  • The ideea is that if you let them expand and put height 50% to each, then the image will take is original height, and will not care about the text. If you don't, that means that your force your image to have a fixed height so it can't take same height as the text container. In your second example, for example, your lower element always has 160.391 height + border-top:1 + border-bottom:1. So is not half either. – Berci Nov 18 '19 at 16:05
  • `width:100%; height:100%` on the image is to work with ` object-fit: cover;` to preserve the aspect ratio of the image being used. Even when trying without an image, and just using varying text the issue still seems to persist. – theHappyDev Nov 18 '19 at 16:27
-1

I have forked your pen. I remove some stuff like the div.item and the need for using height: 100%.

I added 2 examples, the first respecting the aspect ratio of the image but in case you want to have a specific size for the image you can refer to the second one with a fixed size

.flex-container {
  display: flex;
  max-width: 500px;
  flex-flow: row wrap;
  height: auto;
  align-items: stretch;
}
.flex-item {
  display: flex;
  width: 100px;
  margin: 30px;
  flex-direction: column;
}

.upper {
  flex: 1;
  border: 1px solid red;
}

img {
  bottom: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  margin-bottom: 0;
}
.img-size {
  height: 200px;
}

.flex-item2 {
  width: 100px;
  margin: 30px;
  display: flex;
  flex-direction: column;
}
<h1>Attempt 1</h1>
<div class="flex-container">
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p> <p>hello</p> <p>hello</p> <p>hello</p> <p>hello</p> <p>hello</p> <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>  <p>hello</p>  <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
       <p>hello</p>  <p>hello</p>  <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
</div>

<h1>img sized</h1>

<div class="flex-container">
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p> <p>hello</p> <p>hello</p> <p>hello</p> <p>hello</p> <p>hello</p> <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>  <p>hello</p>  <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
       <p>hello</p>  <p>hello</p>  <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
  <div class="flex-item">
      <div class="upper">
        <p>hello</p>
      </div>
      <div class="lower img-size">
        <img src="https://scx1.b-cdn.net/csz/news/800/2019/giantpandame.jpg" />
      </div>
  </div>
</div>

https://codepen.io/afmeva/pen/ZEEVMOy

afmeva
  • 839
  • 7
  • 13
  • 1
    Thanks, I really appreciate the effort. But I am trying to make the image and the teat area both always be 50% of the container's height. – theHappyDev Nov 18 '19 at 15:17