0

This question gets asked a lot, but no one seems to have an answer, other than using JavaScript to calculate the middle row's height using window.innerHeight, and .offsetHeight. That's what I am doing already, but I'd like to do it the "right way" using only native CSS Grid.

I am trying to accomplish this:

+-----------------------------------+
| Header (fixed height in px)       |
|------+-------------------+--------|
|      |                   |        |
| Left |      Center       | Right  |
|      |                   |        |
|      |   fill remaining  |        |
|      |       height      |        |
|      |                   |        |
|------+-------------------+--------|
| Footer (fixed height in px)       |
+-----------------------------------+

So far, I have the following. But it doesn't work if I change header and footer height to a fixed height. It only works cleanly when my heights are all "vh" based and all add up to 100vh.

The grid is exactly what I need except for the fixed height header and footer.

HTML:

<div class="content-main">
    <div class="header">Header</div>
    <div class="left">Left</div>
    <div class="center">Center</div>
    <div class="right">Right</div>
    <div class="footer">Footer</div>
</div>

CSS:

.content-main {
    height: 100vh;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: minmax(auto, auto);
    grid-template-areas:
        "hd hd hd"
        "lt cn rt"
        "ft ft ft";
}

.header {
    grid-area: hd;
    height: 10vh;
}

.left {
    grid-area: lt;
    height: 80vh;
    width: 20vw;
}

.center {
    grid-area: cn;
    height: 80vh;
    width: 60vw;
}

.right {
    grid-area: rt;
    height: 80vh;
    width: 20vw;
}

.footer {
    grid-area: ft;
    height: 10vh;
}
KWallace
  • 1,570
  • 1
  • 15
  • 25
  • [Flexbox](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox) seems a more appropriate tech for the layout you want. – Andy Jul 26 '22 at 13:41
  • Have you tried something like `height: calc(80vh - your-fixed-header-height - your-fixed-footer-height)`? See https://www.w3schools.com/cssref/func_calc.asp – soupy-norman Jul 26 '22 at 13:41
  • Use `grid-template-rows : auto 1fr auto` aside `height:100vh` it should do what you look for to start with. – G-Cyrillus Jul 26 '22 at 14:31

1 Answers1

2

To follow and demonstrate my earlier comment :

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  height: 100vh;
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-rows   : auto 1fr auto;
  grid-template-areas: "hd hd hd" "lt cn rt" "ft ft ft";
  /* why fr and not vw/vh/% ? -> you can add some gaps */
  gap: 3px;
}

div { /* show them and give them a  min-size ,to match  col or row */
  border: solid 1px;
  min-height: 20vh;
  min-width: 20vw;
}

.header {
  grid-area: hd;
}

.left {
  grid-area: lt;
}

.center {
  grid-area: cn;
}

.right {
  grid-area: rt;
}

.footer {
  grid-area: ft;
}
<div class="header">Header</div>
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right">Right</div>
<div class="footer">Footer</div>

min-height instead height can be useful for long contents, so it can push footer down:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-rows   : auto 1fr auto;
  grid-template-areas: "hd hd hd" "lt cn rt" "ft ft ft";
  /* why fr and not vw/vh/% ? -> you can add some gaps */
  gap: 3px;
}

div { /* show them and give them a  min-size ,to match  col or row */
  border: solid 1px;
  min-height: 20vh;
  min-width: 20vw;
}

.header {
  grid-area: hd;
}

.left {
  grid-area: lt;
}

.center {
  grid-area: cn;
}

.right {
  grid-area: rt;
}

.footer {
  grid-area: ft;
}
<div class="header">Header</div>
<div class="left">Left</div>
<div class="center">Center and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br></div>
<div class="right">Right</div>
<div class="footer">Footer</div>

min-height is not what you want?, overflow can avoid content and footer to overlap

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  height: 100vh;
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-rows   : auto 1fr auto;
  grid-template-areas: "hd hd hd" "lt cn rt" "ft ft ft";
  /* why fr and not vw/vh/% ? -> you can add some gaps */
  gap: 3px;
}

div { /* show them and give them a  min-size ,to match  col or row */
  border: solid 1px;
  min-height: 20vh;
  min-width: 20vw;
}

.left,
.center ,
.right {
  overflow:auto;
}
.header {
  grid-area: hd;
}

.left {
  grid-area: lt;
}

.center {
  grid-area: cn;
}

.right {
  grid-area: rt;
}

.footer {
  grid-area: ft;
}
<div class="header">Header</div>
<div class="left">Left</div>
<div class="center">Center and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br> and lots of lines<br></div>
<div class="right">Right</div>
<div class="footer">Footer</div>

For flex, as mention in another comment, you can take a look at other answers of mine Fill remaining vertical space with CSS using display:flex or How can I make my flexbox layout take 100% vertical space?

G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
  • 1
    Excellent comment. I've been terribly busy and haven't had a chance to work through all your examples, but I will as soon as I can. Thanks. I'm not just "taking your answer and running away..." ;-) I think this will def help solve the problem as soon as I can get back to that project. – KWallace Jul 28 '22 at 23:31
  • Sorry it took so long to mark your answer as the accepted answer. – KWallace Aug 17 '22 at 22:08