Multiline grid with elements of same height using flexbox
No, this is not possible with pure CSS/flexbox.
I'll cite the W3C spec:
When a flex container has multiple lines, the cross size of each line is the minimum size necessary to contain the flex items on the line (after aligment due to align-self), and the lines are aligned within the flex container with the align-content property. [...]
(From http://www.w3.org/TR/css3-flexbox/#flex-lines)
So, one item is only expanded to the maximum height of that line it's currently on.
Terminology of the above quote:
(From http://www.w3.org/TR/css3-flexbox/#box-model)
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
themax-content
size of each flex-sized grid track and dividing that
size by the respective flex factor to determine a “hypothetical1fr
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.
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.
Managing CSS flex-box growth in multi-line to create a grid of equal blocks
This is totally possible, however, you have to know how many columns you'll have at a maximum. http://jsfiddle.net/kelunik/C2q8D/6/
Solution
By adding a few empty placeholders, your cards get equally sized. You just have to make sure, you're adding enough placeholders. It doesn't matter if there are too many, because they'll have a height of zero and are not visible.
CSS
section {
display: flex;
flex-flow: row wrap;
background-color: blue;
}
div {
background-color: red;
height: 3rem;
flex: 1 0 10rem;
}
div:nth-child(even) {
background-color: green;
}
div:empty {
margin: 0;
height: 0;
border: 0;
background: transparent;
}
HTML
<section>
<div>a</div>
<div>b</div>
<div>c</div>
<div>d</div>
<div>e</div>
<div>f</div>
<div>g</div>
<div>h</div>
<div>i</div>
<div>j</div>
<div>k</div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
CSS only solution to set MULTIPLE “same height” row sections on a responsive grid
Based on your own answer, where you grouped them by 4, you can do that with CSS Flexbox too.
To make them behave when there is less than 4, it might be possible to accomplish that using the nth-child
selector, but it was simpler to use a last*
class, so I went for the latter.
One might even be able to do this without the .group_of_4
wrapper, with some clever nth-child
rules, but again, went for the simpler since it does not come with any obvious limitations
Fiddle demo
.items { display: flex; flex-direction: column; max-width: 1200px;}
.items .group_of_4 { display: flex; flex-wrap: wrap; justify-content: space-between; /* updated */}
.items .group_of_4 ~ .group_of_4 { margin-top: 24px;}
.items .group_of_4 > div { width: calc(25% - 12px); /* updated */ box-sizing: border-box; padding: 12px;}
.item__heading { background-color: #d4d0f5; padding: 10px; text-align: center; border: 1px solid #bbbbbb; order: 1;}
.item__content { padding: 10px; border-left: 1px solid #bbbbbb; border-right: 1px solid #bbbbbb; order: 2;}
.item__features { padding: 10px; border-left: 1px solid #bbbbbb; border-right: 1px solid #bbbbbb; background-color: #f7cbb1; order: 3;}
.item__price { background-color: #e0f6d9; padding: 10px; text-align: center; border: 1px solid #bbbbbb; order: 4;}
/* one item in a group */.items .group_of_4 .last1 { margin-right: calc(75% 6px); /* updated */}/* two items in a group */.items .group_of_4 .last2 { margin-right: calc(50% + 6px); /* updated */}/* three items in a group */.items .group_of_4 .last3 { margin-right: calc(25% + 6px); /* updated */}
@media (max-width: 600px) { .items .group_of_4 > div:nth-child(8) ~ .item__heading { margin-top: 24px; order: 5; } .items .group_of_4 > div:nth-child(8) ~ .item__content { order: 6; } .items .group_of_4 > div:nth-child(8) ~ .item__features { order: 7; } .items .group_of_4 > div:nth-child(8) ~ .item__price { order: 8; } .items .group_of_4 > div { width: calc(50% - 12px); /* updated */ }
/* one item in a group */ /* three items in a group */ .items .group_of_4 .last1, .items .group_of_4 .last3 { margin-right: 50%; } /* two items in a group */ .items .group_of_4 .last2 { margin-right: 0%; } }
<div class="items">
<div class="group_of_4"> <div class="item__heading"> Item 1 </div> <div class="item__content"> Some content that is not that long </div> <div class="item__features"> <ul> <li>feature 1</li> </ul> </div> <div class="item__price"> £99.99 </div>
<div class="item__heading"> Item 2 </div> <div class="item__content"> Some content that is longer than other items on the same row and sets the height of this section as it spans many more lines than the rest of the other content sections on this row </div> <div class="item__features"> <ul> <li>feature 1</li> </ul> </div> <div class="item__price"> £69.99 </div>
<div class="item__heading"> Item 3 </div> <div class="item__content"> Some content that is not that long </div> <div class="item__features"> <ul> <li>feature 1</li> <li>feature 2</li> <li>feature 3</li> </ul> </div> <div class="item__price"> £69.99 </div>
<div class="item__heading"> Item 4 </div> <div class="item__content"> Some content that is not that long </div> <div class="item__features"> <ul> <li>feature 1</li> </ul> </div> <div class="item__price"> £109.99 </div> </div> <div class="group_of_4"> <div class="item__heading"> Item 5 </div> <div class="item__content"> Some content that is a medium kind of length blah blah </div> <div class="item__features"> <ul> <li>feature 1</li> </ul> </div> <div class="item__price"> £29.99 </div>
<div class="item__heading last2"> Item 6 </div> <div class="item__content last2"> Some content that is not that long </div> <div class="item__features last2"> <ul> <li>feature 1</li> </ul> </div> <div class="item__price last2"> £99.99 </div>
</div></div>
How to vertically stretch only one row in a multi-line flexbox wrapped layout?
Have you considered adding one more div for the first two elements?
* {
font-size: 1.5rem;
margin: 0;
padding: 0;
}
.container {
background: #AAA;
height: 100vh;
display: flex;
flex-direction: column;
align-content: stretch;
}
.container1 {
display: flex;
flex: 1 0;
}
.first {
background: lightblue;
width: 30%;
}
.second {
background: lightyellow;
width: 70%;
}
.third {
background: lightgreen;
}
<body>
<div class="container">
<div class="container1">
<div class="first">First</div>
<div class="second">Second</div>
</div>
<div class="third">Third</div>
</div>
</body>
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 toalign-self
), and the
lines are aligned within the flex container with thealign-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, usevisibility: hidden
.
Revised Fiddle
Related Topics
Make CSS Shimmer Effect Work an Already Loaded Image
Do Inline Elements Establish a Line Box for Their Content
Checkboxes with Font Awesome 5 Icons
Assigning Visible Property of the Button to a Static Method Result
Responsive Design: Centralize a Full-Screen Square in Any Screen Size
How to Minify CSS Files with Requirejs
Bootstrap 3 - Add an Asterisk to the Input on the Same Row
Div Side by Side Without Float
Make Div Fill Remainder of Page Vertically
Font Weights Differing in Webkit and Firefox
Cutting a Triangle Out of Div, But Have It Horizontally Centered
How to Manage My CSS as Modx Resources
Decrease the Tabs Bar Height in Gnome Terminal
CSS - How to Select Multiple Different Child Elements Within a Parent Without Repeating the Parent
iOS Safari Transition Transform Not Working
CSS Media Query to Handle New High Resolution Mobiles Whilst Ignoring Tablets