Search code examples
htmlcsslayoutcss-grid

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;


Solution

  • 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