CSS only solution to set same height row sections on a responsive grid
By giving the .items
display: flex; flex-wrap: wrap;
your item
will become flex items and flow from left to right and wrap when there is no more space.
Then you give the .item
display: flex; flex-direction: column;
, which will make them a flex container as well, and by using column direction, its children will flow vertically, like block elements.
Finally you give the .item__content
flex: 1;
, which will make it take any remaining space, vertically, hence every row's item
will have equal height.
Updated codepen
Stack snippet
.items { display: flex; flex-wrap: wrap; max-width: 1200px;}
.item { display: flex; flex-direction: column; width: 25%; box-sizing: border-box; vertical-align: top; padding: 0 12px; margin: 24px -4px 24px 0;}
@media (max-width: 600px) { .item { width: 50%; }}
.item__heading { background-color: #d4d0f5; padding: 10px; text-align: center; border: 1px solid #bbbbbb;}
.item__content { flex: 1 1 auto; /* IE need 1 1 auto */ padding: 10px; border-left: 1px solid #bbbbbb; border-right: 1px solid #bbbbbb;}
.item__price { background-color: #e0f6d9; padding: 10px; text-align: center; border: 1px solid #bbbbbb;}
<div class="items">
<div class="item"> <div class="item__heading"> Item 1 </div> <div class="item__content"> Some content that is not that long </div> <div class="item__price"> £99.99 </div> </div>
<div class="item"> <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 </div> <div class="item__price"> £69.99 </div> </div>
<div class="item"> <div class="item__heading"> Item 3 </div> <div class="item__content"> Some content that is not that long </div> <div class="item__price"> £69.99 </div> </div>
<div class="item"> <div class="item__heading"> Item 4 </div> <div class="item__content"> Some content that is not that long </div> <div class="item__price"> £109.99 </div> </div>
<div class="item"> <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__price"> £29.99 </div> </div>
<div class="item"> <div class="item__heading"> Item 6 </div> <div class="item__content"> Some content that is not that long </div> <div class="item__price"> £99.99 </div> </div>
</div>
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>
Equal column height in multi-column responsive design
For the behaviour you want, you'll have to make your .col display:inline-block;
, remove the float altogether and then you'll probably want to also add vertical-align:top;
How do I keep two side-by-side div elements the same height?
Flexbox
With flexbox it's a single declaration:
.row {
display: flex; /* equal height of the children */
}
.col {
flex: 1; /* additionally, equal width */
padding: 1em;
border: solid;
}
<div class="row">
<div class="col">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</div>
<div class="col">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad omnis quae expedita ipsum nobis praesentium velit animi minus amet perspiciatis laboriosam similique debitis iste ratione nemo ea at corporis aliquam.</div>
</div>
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 of elements inside grid item with CSS grid layout
Is it even possible?
tldr; Yes.
Codepen Demo #1
Codepen Demo # 2 (Uses SASS and is configurable)
The difficulty here is that each article is a grid within itself and therefore any one article has no knowledge about another. Because of this, there is no way for a component of one article like a header to adjust according to the height of a header in another article.
There is actually a way to pull this off with css grids & without changing any markup!
We could 'flatten' the structure with CSS such that all the components of all the articles are part of just one CSS grid - the article container.
This is possible without even changing the current markup by setting the articles with display: contents
display: contents (caniuse)
From Caniuse:
display: contents
causes an element's children to appear as if they
were direct children of the element's parent, ignoring the element
itself. This can be useful when a wrapper element should be ignored
when using CSS grid or similar layout techniques.
So if we set the articles with display: contents
.container article {
display: contents;
}
Now all of the headers, sections and footer become (direct) grid items (of the container - which has display:grid
) which we can arrange using the grid-template-areas
property.
.container {
display: grid;
grid-column-gap: 1em; /* horizontal gap between articles */
grid-template-columns: repeat(3, 1fr);
grid-template-areas: "header1 header2 header3"
"section1 section2 section3"
"footer1 footer2 footer3"
"header4 header5 header6"
"section4 section5 section6"
"footer4 footer5 footer6"
}
Since each header/section/footer take up exactly one cell - this forces them to take up the same vertical height. So e.g. header1,header2 and header3 will all have the same height regardless of their content.
Now set the grid-area
properties on each of the cells.
article:nth-child(1) header {
grid-area: header1;
}
article:nth-child(2) header {
grid-area: header2;
}
article:nth-child(3) header {
grid-area: header3;
}
article:nth-child(4) header {
grid-area: header4;
}
article:nth-child(1) section {
grid-area: section1;
}
...
article:nth-child(4) section {
grid-area: section4;
}
article:nth-child(1) footer {
grid-area: footer1;
}
...
article:nth-child(4) footer {
grid-area: footer4;
}
Finally, set a vertical gap between each row of articles (starting from the second row of articles):
article:nth-child(n + 4) header {
margin-top: 1em;
}
Demo:
body { width: 100%; max-width: 1024px; margin: auto;}
.container { display: grid; grid-column-gap: 1em; grid-template-columns: repeat(3, 1fr); grid-template-areas: "header1 header2 header3" "section1 section2 section3" "footer1 footer2 footer3" "header4 header5 header6" "section4 section5 section6" "footer4 footer5 footer6"}
.container article { display: contents;}
article header { background-color: #eeeeee;}
article section { background-color: #cccccc;}
article footer { background-color: #dddddd;}
article:nth-child(n + 4) header { margin-top: 1em;}
article:nth-child(1) header { grid-area: header1;}article:nth-child(2) header { grid-area: header2;}article:nth-child(3) header { grid-area: header3;}article:nth-child(4) header { grid-area: header4;}article:nth-child(1) section { grid-area: section1;}article:nth-child(2) section { grid-area: section2;}article:nth-child(3) section { grid-area: section3;}article:nth-child(4) section { grid-area: section4;}article:nth-child(1) footer { grid-area: footer1;}article:nth-child(2) footer { grid-area: footer2;}article:nth-child(3) footer { grid-area: footer3;}article:nth-child(4) footer { grid-area: footer4;}
<div class="container"> <article> <header> <h2>Header</h2> <h2>Header</h2> </header> <section> <p>Content</p> </section> <footer> <p>Footer</p> </footer> </article> <article> <header> <h2>Header</h2> </header> <section> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> </section> <footer> <p>Footer</p> <p>Footer</p> </footer> </article> <article> <header> <h2>Header</h2> </header> <section> <p>Content</p> <p>Content</p> <p>Content</p> </section> <footer> <p>Footer</p> </footer> </article> <article> <header> <h2>Header</h2> </header> <section> <p>Content</p> <p>Content</p> <p>Content</p> <p>Content</p> </section> <footer> <p>Footer</p> <p>Footer</p> </footer> </article></div>
Is there a CSS only solution to make divs equal height in a vertical grid?
You can use a wrapping flexbox
- see how the heights are auto-adjusted (due to the align-items:stretch
property which is default) when the child divs wrap as you resize the window.
* { box-sizing: border-box;}body { margin: 0;}.wrapper { display: flex; flex-flow: row wrap;}.wrapper > div { border: 1px solid red;}
<div class="wrapper"> <div> some text here some text here </div>
<div> some text here <br/>more text here </div>
<div> some text here <br/>more text here and some more and some more </div>
<div> some text here <br/>more text here <br/>more text here </div>
</div>
Related Topics
HTML Video Player Plays Sound But Not Video
How to Make Rooftext Effect and Valley Text Effect in HTML5 (Or Fabric.Js)
Why Is an Element with Position: Fixed Moving with a Non-Positioned Sibling
Export HTML Table to Excel Using ASP.NET
How to Center List Items Inside a Ul Element
Decode HTML Entities in Android
Html5 Iframe Seamless Attribute
Dynamically Aligning Pseudo Element According to Parent Height
CSS Object-Fit: Contain; Is Keeping Original Image Width in Layout
Using Z-Index to Get Div Above Another Div
How to Disable Form Fields Using CSS
Table Scroll with HTML and CSS
Adding a Background Image to a <Div> Element
Add a Pipe Separator After Items in an Unordered List Unless That Item Is the Last on a Line