Equal Height Rows in a Flex Container

Equal height rows in a flex container

The answer is NO.

The reason is provided in the flexbox specification:

6. Flex Lines

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.

In other words, when there are multiple lines in a row-based flex container, the height of each line (the "cross size") is the minimum height necessary to contain the flex items on the line.

Equal height rows, however, are possible in CSS Grid Layout:

  • Equal height rows in CSS Grid Layout

Otherwise, consider a JavaScript alternative.

Using flexbox for equal height rows when split in columns

Make two adjustments to make the layout work.

Add this to your code:

.flex-rows {
flex: 1; /* gives this container the height of its parent */
}

.row-flex:last-child {
margin-top: auto; /* spaces siblings away to the extremes;
.row-flex:first-child { margin-bottom: auto } would also work;
and so would justify-content: space-between on the container
(which would save you from having to create this new rule; */
}

In the revised code below, I've commented out what appear to be unnecessary rules.

.flex-cols {  display: flex;  /* width: 100%; */  /* flex-direction: row; */}
.col-flex { display: flex; flex: 1; /* flex-basis: 100%; */ flex-direction: column; margin-right: 20px; border: 1px solid green; padding: 5px;}
.flex-rows { flex: 1; /* ADDITION #1 */ display: flex; /* width: 100%; */ flex-direction: column;}
.row-flex { border: 1px solid red; display: flex; /* flex: 1; */ /* flex-basis: 100%; */ flex-direction: column; margin-bottom: 20px;}
.row-flex:last-child { margin-top: auto; /* ADDITION #2 */}
<div class="flex-cols">  <div class="col-flex">    <div class="flex-rows">      <div class="row-flex">        Hello      </div>      <div class="row-flex">        World      </div>    </div>  </div>  <div class="col-flex">    <div class="flex-rows">      <div class="row-flex">        Hello, hello, hello! This is a bunch of extra text to explain what should happen. Ideally, this will take up as much room as needed, and the div below will take up an equal amount to force a vertical 50/50 split.      </div>      <div class="row-flex">        World      </div>    </div>  </div>   <div class="col-flex">    <div class="flex-rows">      <div class="row-flex">        Hello      </div>      <div class="row-flex">        World      </div>    </div>  </div></div>

CSS Flex: How to get equal heights in flex rows

flex-grow works this way: it takes available space and distributes it only after applying flex-basis (which when auto takes its value from width or height, in current case it's height because of flex-direction: column). In current case flex-basis is auto because height is also. If after applying flex-basis no free space will remain, flex-grow won't work.

So you have several options here: set height: 0 or set flex-basis: 0. Also you might need min-height: 0 (because min-height: auto in some cases don't allow flex-item to occupy less then its content).

Demo:

.row-container {  display: flex;  flex-direction: column;  height: 300px;  width: 75%;  border: 1px solid blue;}
.flex-row { border: 1px solid black; flex-grow: 1; flex-basis: 0; /* or height: 0; */ /* if needed add min-height: 0; */ display: flex; background-color: yellow; align-items: center;}
.col-1,.col-2 { border: 1px solid green;}
.col-right { padding-left: 10px;}
<div class="some-div">  <div class="row-container">    <div class="flex-row">      <div class="col-wrapper">        <div class="col-1">X</div>        <div class="col-2">some content</div>      </div>    </div>    <div class="flex-row">      <div class="col-wrapper">        <div class="col-1">XXX</div>        <div class="col-2">some longer content</div>      </div>    </div>    <div class="flex-row">      <div class="col-wrapper">        <div class="col-1">aa ab</div>        <div class="col-2">Amet illo distinctio facilis blanditiis alias. Explicabo dolores asperiores ducimus aut officiis, vero? Accusantium in accusantium ipsa iusto velit? Quas nesciunt ipsam amet impedit adipisci odio Omnis nemo perspiciatis quibusdam</div>      </div>    </div>  </div></div>

Give equal height to children of elements within a flex container

The flex properties on the parent container (container in your example) don't pass down to the child elements, even if they are also containers. Therefore you also need to make the col divs display:flex, as follows:

.col  {
flex: 1;
display: flex; /* make this a flex container so it has flex properties */
justify-content: center; /* to horizontally center them in this flex display */
/* REST OF YOUR CSS HERE */
}

Note that you also need to add flex: 1; to the content itself so it doesn't shrink, e.g.:

.col-item {
flex: 1;
/* REST OF YOUR CSS HERE */
}

Working Example with your code:

.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-content: center;
}

.col {
flex: 1;
background: orange;
margin: 1px;
display: flex;
justify-content: center;
}

.col-item {
flex: 1;
margin: 15px;
}
<html>

<body>
<div class="container">
<div class="col">
<div class="col-item" style="background: red;">
<h2>Column 1</h2>
<p>Hello World</p>

</div>
</div>
<div class="col">
<div class="col-item" style="background: red;">
<h2>Column 2</h2>
<p>Hello World!</p>
<p>Hello World!</p>
<p>Hello World!</p>
<p>Hello World!</p>

</div>
</div>
<div class="col">
<div class="col-item" style="background: red;">
<h2>Column 3</h2>
<p>Some other text..</p>
<p>Some other text..</p>
</div>
</div>
</div>
</body>

</html>

Equal height sections within flexbox columns?

Since both columns are inside the same flex container, yes, the list boxes can be the same height (based on the tallest content) using only CSS.

.columns {  display: flex;}
.col { display: flex; /* new */ flex-direction: column; /* new */ margin-left: 20px;}
.list { flex: 1; /* new */ padding: 24px; border: 1px solid blue;}
ul { margin: 0;}
<div class="columns">  <div class="col">    <h3>Header</h3>    <div class="list">      <ul>        <li>List item</li>        <li>List item</li>      </ul>    </div>  </div>  <div class="col">    <h3>Header</h3>    <div class="list">      <ul>        <li>List item</li>        <li>List item</li>        <li>List item</li>        <li>List item</li>      </ul>    </div>  </div></div>

Equal height rows in flex-direction: column

The flex equal height columns feature – which is the result of align-items: stretch, a default setting of a flex container – applies only to flex items on the same row.

It doesn't work for items in a multi-line flex container. This behavior is defined in the spec:

6. Flex Lines

In a multi-line flex container (even one with only a single line), the
cross size of each line is the minimum size necessary to contain the
flex items on the line (after alignment due to align-self), and the
lines are aligned within the flex container with the align-content
property.

In other words, when there are multiple lines in a row-based flex container, the height of each line (the "cross size") is the "minimum size necessary to contain the flex items on the line".

In addition, because align-items: stretch works along the cross-axis, the equal height columns feature is useless in flex-direction: column, where the cross-axis is horizontal.

To achieve equal height columns/rows across multiple lines consider a Javascript solution.


However, without knowing much about your overall objective, here's a simple way to achieve equal height rows in your current layout:

Add duplicate content in both divs. In the .component.left div, use visibility: hidden.

Revised Fiddle

Equal height rows in CSS Grid Layout

Short Answer

If the goal is to create a grid with equal height rows, where the tallest cell in the grid sets the height for all rows, here's a quick and simple solution:

  • Set the container to grid-auto-rows: 1fr

How it works

Grid Layout provides a unit for establishing flexible lengths in a grid container. This is the fr unit. It is designed to distribute free space in the container and is somewhat analogous to the flex-grow property in flexbox.

If you set all rows in a grid container to 1fr, let's say like this:

grid-auto-rows: 1fr;

... then all rows will be equal height.

It doesn't really make sense off-the-bat because fr is supposed to distribute free space. And if several rows have content with different heights, then when the space is distributed, some rows would be proportionally smaller and taller.

Except, buried deep in the grid spec is this little nugget:

7.2.3. Flexible Lengths: the fr
unit

...

When the available space is infinite (which happens when the grid
container’s width or height is indefinite), flex-sized (fr) grid tracks are
sized to their contents while retaining their respective proportions.

The used size of each flex-sized grid track is computed by determining
the max-content size of each flex-sized grid track and dividing that
size by the respective flex factor to determine a “hypothetical 1fr
size”.

The maximum of those is used as the resolved 1fr length (the
flex fraction), which is then multiplied by each grid track’s flex
factor to determine its final size.

So, if I'm reading this correctly, when dealing with a dynamically-sized grid (e.g., the height is indefinite), grid tracks (rows, in this case) are sized to their contents.

The height of each row is determined by the tallest (max-content) grid item.

The maximum height of those rows becomes the length of 1fr.

That's how 1fr creates equal height rows in a grid container.


Why flexbox isn't an option

As noted in the question, equal height rows are not possible with flexbox.

Flex items can be equal height on the same row, but not across multiple rows.

This behavior is defined in the flexbox spec:

6. Flex Lines

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.

In other words, when there are multiple lines in a row-based flex container, the height of each line (the "cross size") is the minimum height necessary to contain the flex items on the line.



Related Topics



Leave a reply



Submit