Ben Souchet
Ben Souchet

Reputation: 1532

CSS Grid : row not taking full height space available

I want to achieve a pretty simple layout using a css grid (not flexbox) :

enter image description here

Currently I have this (similar but with an unwanted empty white area):

enter image description here

My question is what is the missing part(s) in my exemple code to achieve the desired layout ?

The issue seems very similar to this question: How to make CSS Grid items take up remaining space?
And this one: How do you collapse unused row in a CSS grid?

But... a little bit more complicated since I have one more row

I have a green div on the last row, this last row need to grow with the page height.
To do that the row template for this last row is set to 1fr.

My current code

You can check the very simple code snippet below:

html {
    height: 100%;
}
body {
    height: 100vh;
}
.container {
    display: grid;
    grid-template-columns: 180px 1fr;
    grid-template-rows: min-content auto 1fr;
    height:100%;
}

.red-cube {
    background-color: red;
    width: 100%;
    Height: 180px;
    grid-column: 1;
    grid-row: 1 / 3;
}
h1, h2 {
    margin: 0;
    padding: 0;
}
.blue-title {
    background-color: blue;
    grid-column: 2;
    grid-row: 1;
    height: fit-content;
}
.yellow-div {
    background-color: yellow;
    grid-column: 2;
    grid-row: 2;
    height: 100%;
}
.green-content {
    background-color: green;
    grid-column: 1 / 3;
    grid-row: 3;
    align-self: stretch;
}
<div class="container">
    <div class="red-cube"></div>
    <h1 class="blue-title">Title</h1>
    <div class="yellow-div"><h2>Second line</h2></div>
    <div class="green-content"><p>Some text</p></div>
</div>

Or play with the snippet on Codepen here.

Failed approach

I tested the solution of setting the grid-template-rows value of the yellow row to 1fr to consume the free space remaining. (the solution of the Stackoverflow question I mentioned before)

i.e. Replacing grid-template-rows: min-content auto 1fr; with grid-template-rows: min-content 1fr 1fr;

But this will break the green div that need to grow with the page height because we will have two rows with a setting of 1fr.

Conclusion

I wonder if there is a solution without switching to flexbox or creating multiple grid layout (reorganize the layout).

I also don't want to "hardcode" the row height by putting something like : grid-template-rows: 1.25rem auto 1fr;

Upvotes: 2

Views: 2654

Answers (2)

Ben Souchet
Ben Souchet

Reputation: 1532

After lot of tests, I found a way to achieve the result I wanted without touching the HTML layout.

To force the grid algorithm to consume the free space available in the second row it's currently required to use a row height in fractional unit (fr).
So in the CSS I added a row with a height of 0fr (YES, 0 fraction is considered valid and trigger the grid algorithm).

  • Now the red square (🟥) is on rows 1 & 2.
  • The blue title (🟦) is on row 1.
  • The yellow sub-title (🟨) is on row 2 & 3 (the third row is the special 0fr row).
  • And the green text (🟩) is on row 4.

The result: enter image description here

Code snippet:

html {
    height: 100%;
}
body {
    height: 100vh;
}
.container {
    display: grid;
    grid-template-columns: 180px 1fr;
    grid-template-rows: min-content auto 0fr 1fr;
    height:100%;
}

.red-cube {
    background-color: red;
    width: 100%;
    Height: 180px;
    grid-column: 1;
    grid-row: 1 / 3;
}
h1, h2 {
    margin: 0;
    padding: 0;
}
.blue-title {
    background-color: blue;
    grid-column: 2;
    grid-row: 1;
    height: fit-content;
}
.yellow-div {
    background-color: yellow;
    grid-column: 2;
    grid-row: 2 / 4;
    height: 100%;
}
.green-content {
    background-color: green;
    grid-column: 1 / 3;
    grid-row: 4;
    align-self: stretch;
}
<div class="container">
    <div class="red-cube"></div>
    <h1 class="blue-title">Title</h1>
    <div class="yellow-div"><h2>Second line</h2></div>
    <div class="green-content"><p>Some text</p></div>
</div>

I tested this solution on Chrome, Firefox & Safari and they all give the wanted result ;)

You can also play with this Codepen version: https://codepen.io/BSO__/pen/wvrEBWx

Upvotes: 1

micahlt
micahlt

Reputation: 424

It looks like the easiest solution for this would be a nested grid setup (not to be confused with subgrid). Move the .green-content div outside of the .container grid. Then set up the body as a grid with two rows - the first with a height of 180px and the second with a height of 1fr. The 180-pixel row will serve as the parent to the .container grid. Note that you could also use a different element besides the body to serve as the parent grid if you don't want to use the entire page. The snippet below is a working example

html {
    height: 100%;
}

body {
    height: 100vh;
    display: grid;
    grid-template-rows: 180px 1fr;
}

.container {
    display: grid;
    grid-template-columns: 180px 1fr;
    grid-template-rows: max-content 1fr;
}

.red-cube {
    background-color: red;
    width: 100%;
    height: 180px;
    grid-column: 1;
    grid-row: 1 / 3;
 }

h1, h2, p {
    margin: 0;
    padding: 0;
}

.blue-title {
    background-color: blue;
    grid-column: 2;
    grid-row: 1;
    height: fit-content;
 }

 .yellow-div {
    background-color: yellow;
    grid-column: 2;
    grid-row: 2;
    height: 100%;
 }

.green-content {
    background-color: green;
    margin-top: 0;
}
<div class="container">
    <div class="red-cube"></div>
    <h1 class="blue-title">Title</h1>
    <div class="yellow-div"><h2>Second line</h2></div>
</div>
<div class="green-content"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ac accumsan eros. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed dictum in magna eu luctus. Fusce feugiat lectus tortor, eget consectetur augue convallis non. Aliquam massa tortor, fermentum eu nibh non, sollicitudin molestie mi. Ut nec eros sagittis sapien tristique accumsan. Vivamus dapibus, nulla vitae facilisis volutpat, velit odio viverra nisl, non tempor erat mi condimentum velit. Duis posuere sem arcu, venenatis condimentum lorem efficitur eu. Quisque et mi quis lorem pellentesque ultrices. Ut felis lacus, vestibulum sit amet libero non, viverra condimentum turpis. Phasellus massa quam, vestibulum sit amet fermentum molestie, egestas in velit. Donec tristique tempus urna. Nullam pellentesque volutpat mattis. Nunc volutpat orci vel dolor ultrices vestibulum.

Aenean volutpat lacus vitae vehicula semper. Nunc volutpat auctor ligula. Nulla sed augue sem. Vestibulum suscipit ante ac mi viverra, quis feugiat orci posuere. Quisque sit amet tortor luctus, mollis neque a, varius velit. Maecenas sed pulvinar eros, at pretium diam. Duis tellus leo, blandit eget turpis eu, ultricies condimentum dolor. Aliquam erat volutpat. Duis convallis enim lacus, vitae placerat dui dictum convallis. Suspendisse viverra magna vel tellus condimentum, vel pharetra lacus rhoncus. Nam quis mattis elit. Nullam ultricies metus odio, a lobortis quam pharetra sed. Suspendisse vestibulum ullamcorper neque, condimentum euismod ex venenatis ac. Aenean vitae ex eget ligula ultricies condimentum. Donec quis nibh nec massa rutrum dignissim non eget tortor.

Praesent sollicitudin varius diam vel hendrerit. Ut sit amet finibus turpis, sit amet rutrum quam. Sed vestibulum tortor vel quam viverra ullamcorper. Aliquam erat volutpat. Sed gravida, risus vitae dignissim ornare, felis ante vestibulum sapien, nec tempor eros arcu in enim. Nullam suscipit mollis arcu non aliquet. Aenean sit amet nisl dui. In euismod turpis et velit pellentesque fringilla. Ut ut quam lobortis neque egestas pulvinar ac nec ante. Donec tortor odio, posuere eget congue vitae, accumsan eget nisl. Curabitur nunc urna, elementum id erat a, viverra maximus eros. Proin dictum eget ante eget aliquam. Aenean sit amet diam imperdiet, lobortis diam ultricies, dapibus velit.

Morbi neque lectus, cursus in sagittis quis, sollicitudin ac elit. Aenean porta dui in euismod bibendum. Morbi lacus felis, mattis nec feugiat non, laoreet et nibh. Suspendisse mauris arcu, fringilla vitae dolor a, finibus venenatis metus. Etiam justo nunc, eleifend pretium nibh nec, euismod luctus justo. Pellentesque risus leo, congue vel metus a, gravida volutpat arcu. In iaculis sollicitudin tincidunt.

Donec ac leo id nisl malesuada viverra et id libero. Aliquam scelerisque efficitur ipsum a imperdiet. Curabitur porttitor lorem quis orci luctus, at tincidunt leo tempor. Aenean condimentum feugiat sapien, id mattis justo dignissim a. Cras quis odio a quam euismod placerat et in ex. Nulla consequat scelerisque nisl eget faucibus. Mauris eros mauris, ultricies sit amet ex accumsan, pellentesque sagittis tortor. Nam fringilla interdum quam, sed ullamcorper neque egestas id. Proin sed mattis tortor, ac auctor arcu. Cras eu neque mauris. Praesent gravida, libero eget ornare tincidunt, nibh justo consequat lorem, mattis facilisis nibh massa eu urna.</p></div>

This may not be the most elegant solution, but it saves you from having to mess with calc() or defining specific heights in rems.

Upvotes: 1

Related Questions