0

Thanks to the answers to my question here (How do I determine the height of a row?) I now understand (looking at the example below) that by setting an explicit height of 60px on a flex-item in the first flex-line, it reduces the height align-content: stretch has to 'play' with from 200px (height of the container) to 140px. As there are 2 flex-lines, this gets split in half to give 70px to the first flex-line and 70px to the second. Now the height of the first flex-line has the height of the tallest flex-item on that line (60px) plus 70px to give 130px. And the height of the second flex-line is 70px.

In practicality, the heights for each flex-line is slightly different (about 122px for the first flex-line 78px for the second) I've been told that has something to do with the height of the text-content.

Would someone be able to elaborate?

.flex-container {
  display: flex;
  flex-wrap: wrap;
  width: 400px;
  height: 200px;
  border: 1px solid black;
}

.flex-container> :nth-child(1) {
  background-color: darkorchid;
  height: 60px;
}

.flex-container> :nth-child(2) {
  background-color: darkkhaki;
}

.flex-container> :nth-child(3) {
  background-color: dodgerblue;
}

.flex-container> :nth-child(4) {
  background-color: darkgoldenrod;
}

.flex-container> :nth-child(5) {
  background-color: darkcyan;
}
<div class="flex-container">
  <span>I am number 1</span>
  <div>I am number 2</div>
  <div>I am number 3</div>
  <div>I am number 4</div>
  <span>I am number 5</span>
</div>
tonitone106
  • 149
  • 7

1 Answers1

2

Edited the whole answer relative to Temani Afif's important key points that i didn't even think about.


To determine the height of a single flex line in a multi lines flex container, We only need to find the free space.

To find the free space we need to find the height of the tallest flex item in each line before stretch is applied.

Assuming that we know the height of all tallest flex items in each flex line we then follow the formula

  1. Free Space: Container height - Sum of all tallest flex item's heights
  2. Equally Distributed free space: Free space / Number of flex lines

Then we take the Equally Distributed free space and add to it the height of the tallest flex item's height which then will give us the height of that flex line.


Example

Arguments:

  • Container height is 300px
  • 3 flex lines
  • Height of the tallest flex item in the first flex line is 30px
  • Height of the tallest flex item in the second flex line is 20px
  • Height of the tallest flex item in the third flex line is 70px

Free space is 180px

Free Space: Container height - Sum of all tallest flex item's heights
300px - (30px + 20px + 70px) = 180px

Equally Distributed free space is 60px

Equally Distributed free space: Free space / Number of flex lines
180px / 3 = 60px

Now we add the Equally Distributed free space to the height of the tallest flex item in each line

  • Height of the first flex line is 30px + 60px = 90px
  • Height of the second flex line is 20px + 60px = 80px
  • Height of the third flex line is 70px + 60px = 130px

[flex]{
    display: flex;
    flex-wrap: wrap;
    height: 300px;
    width: 200px;
    background-color: #0000008f;
/*     align-items:flex-start; */
}

[flex] * {
    width: 100px;
}

[flex] :nth-child(1) {
    background-color: darkorchid;
}

[flex] :nth-child(2) {
    background-color: darkkhaki;
    height: 30px;
}

[flex] :nth-child(3) {
    background-color: dodgerblue;
}

[flex] :nth-child(4) {
    background-color: darkgoldenrod;
    height: 20px;
}

[flex] :nth-child(5) {
    background-color: darkcyan;
}

[flex] :nth-child(6) {
    background-color: darkred;
    height: 70px;
}
<div flex>
  <div></div>
  <div>height : 30px</div>
  <div></div>
  <div>height : 20px</div>
  <div></div>
  <div>height : 70px</div>
</div>

Use devTool to check the height of the stretched flex items.


Now we know how to calculate the height of flex lines, We just need to find the arguments.

Container height

This one is pretty simply, if we don't have a set height on the container it will be equal to content therefore the tallest flex item will define the height of the flex line, The same would happen If the container height is shorter.


Flex lines count

This can be tricky because with flex-wrap:wrap; the lines count will change all the time


Height of the tallest flex item in each flex line

This is the most important bit of information and the most difficult to find

There's two methods That i can think of:

First method

Apply align-items:flex-start and simply get the height of all flex items and compare them then reset back to align-items:stretch

Second method

We need to get the height of all flex items before align-items:stretch which is the height of the text or if there's a set height.

If there's a set height, Simply get that height.

To determine the height of the actual text There's a lot to account for,

  1. How many lines of text are there
  2. line-height
    • If line-height:normal; account for font-family and font-size
    • If line-height:1; (unitless value) account for font-size
    • If line-height:30px; (fixed value) account for line-height only
    • If line-height:30%; (relative value) account for parent's font-size
  3. Any css property that can add to the height like padding border vertical-align on nested inline elements
  4. There's probably more, i will be adding to this list in future edits.
Rainbow
  • 6,772
  • 3
  • 11
  • 28
  • Simple and it worked - thanks! Going forward I’m going to use this slight change to the formulae. What do you think? Free space = Container height - tallest-item on every flex-line. Equally Distributed space = Free space / number of lines. Flexline-height = tallest-item on every flex-line + distributed space. – tonitone106 Jun 14 '20 at 21:52
  • `tallest-item on every flex-line` seems more accurate Yet not appropriate for the last calculation because that is content's height not tallest item *(i never was very good at naming)* **Note:** you forgot to include the font size to find the free space, – Rainbow Jun 14 '20 at 23:55
  • sorry but your formula isn't 100% correct. We should not consider font-size to find the height, we should only consider line-height. It's about the height of line-boxes which is only defined by line-height and by default the line-height is a multiplier of font-size (not equal to 1 but around 1.2). Set an explicit pixel value for line-height and you will see that font-size play no role here because it does only define the height of content area and never the height of line boxes (what we need to consider here). – Temani Afif Jun 15 '20 at 08:22
  • @TemaniAfif That is actually accurate when i was testing i only used `font: 20px/1 ahem;` because i hardly ever change the line height nor use pixels for it, I didn't consider it would have anything to do with anything – Rainbow Jun 15 '20 at 10:40
  • it was accurate because you are in a particular case where (1) you set line-height to 1 so equal to font-size (2) you have only 1 line of text (so only one linebox) (3) you have no vertical alignment involved. Here is an example where a vertical alignment will broke the calculation: https://jsfiddle.net/5zcteap6/. Also note that the font-family will have no impact on this and the result should be the same with any font. Here is a related question to show that the caclulation involve more than the font-size: https://stackoverflow.com/a/61835863/8620333 – Temani Afif Jun 15 '20 at 10:54
  • removing stretch will clearly show this: https://jsfiddle.net/5zcteap6/1/ so the formula should indeed consider the tallest item for each line and to find the tallest item you need to apply a whole set of rules to identify the height of each one – Temani Afif Jun 15 '20 at 10:56
  • @TemaniAfif The idea was to find the height of flex items when they get stretched, removing stretch shows that it's just the content, Also the current formula works for more than one flex line if the line height is 1, It does not break here https://jsfiddle.net/5zcteap6/ ? – Rainbow Jun 15 '20 at 11:04
  • removing stretch will make you easily see the initial height of each element that will be used to find the free space. That free space will define the height of the flex lines and later the stretch effect will make the element take all the space of the flex lines (you can see that removing stretch won't move the element because the height of the flex lines won't change). In the example with vertical-align you can see that the sizes are no more 120px/80px but a little different because if you remove the stretch you will see that the initial height of #4 is a little bigger due to the alignment – Temani Afif Jun 15 '20 at 11:10
  • And I was refering to the text lines (not the flex lines) when talking about line height because an element with 2 lines of text will make things different: https://jsfiddle.net/9456gjes/ because we will have 2 lines boxes inside the element that will define a different initial height to our element: https://jsfiddle.net/9456gjes/1/ (a height logically equal to 2xline-height and in your case 2x font-size) but if you again change the vertical-align, the calculation will be different: https://jsfiddle.net/9456gjes/2/ and no more 2xfont-size – Temani Afif Jun 15 '20 at 11:14
  • I see it, This is far more complicated than i initially thought, this answer is not even close. – Rainbow Jun 15 '20 at 11:19
  • @TemaniAfif Is this a better formulae? Free space = Container height - line-box height of every row (if `flex-direction: row;`). Equally Distributed space = Free space / number of line-boxes. Line-box height = original line-height + equally-distributed space – tonitone120 Sep 26 '20 at 23:43