I have a CSS grid with a row div for a header, a row div for content, and a row div for a footer. I want the content to fill the screen but keep the header and footer visible. I have a fixed-size div inside another div inside the content div. Everything except the fixed-size div is height: 100%.
If I apply overflow-y: auto to the content div, the scrollbar appears on the content div. This is great, but what I really want is for the scrollbar to appear on the div inside the content div instead.

https://jsfiddle.net/efth2akr/2/
If I apply overflow-y: auto to the div inside the content div instead, there is no scrollbar and the content div takes on the height of the fixed-size div. This pushes the footer down and puts a scrollbar on the whole page. What?? Isn't height: 100% supposed to be based on the parent height? Other questions that describe similar scenarios fail to put height: 100% all the way up the chain, but I haven't.

https://jsfiddle.net/t08u9wnk/2/
How can I achieve my desired behavior of having the scrollbar appear on the div inside the content div while maintaining a responsive layout? What am I not understanding about height: 100% in this scenario?
Browser: Microsoft Edge 103.0.1264.62
I have been bitten by this unintuitive design choice of CSS grid: https://github.com/w3c/csswg-drafts/issues/1777
In summary, CSS grid "1fr" behaves like minmax(auto, 1fr) (where 1fr is the actual fractional dimension of the grid). The minimum width/height of a "1fr" grid row/column is the auto width/height. If the auto width/height is larger than 1fr, the whole row/column will expand out past 1fr because minmax ignores the max when min > max!
This is why my problem has the same symptoms as all the other questions about height: 100% not working where the answer was that they had an ancestor with height: auto. It turns out 1fr can become auto!
Replacing:
grid-template-rows: auto 1fr auto;
with:
grid-template-rows: auto minmax(0, 1fr) auto;
fixes the problem.
https://jsfiddle.net/t08u9wnk/3/
I think the approach you are trying to follow would work only if you set a fixed height or max-height to div.grid-content > div. Now the problem is that the height of this container is dynamic and depends on height: 100%, so you might be tempted to do max-height: 100% but here is a good reason for why this is not possible.
If you want div.grid-content > div to have a scroll and keep the layout of the entire page based on the height of the screen, I'd propose you to use an absolute positioned overlay.
Here is a modified snippet of your code explaining how it works:
html, body {
height: 100%;
width: 100%;
}
body {
/* prevents scroll on the entire page */
overflow: hidden;
}
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div.grid {
display: grid;
grid-template-rows: auto 1fr auto;
grid-template-columns: 1fr;
height: 100%;
width: 100%;
}
div.grid-header, div.grid-footer {
background-color: #ff0000;
}
div.grid-content {
background-color: #00ff00;
/* set relative positioning to contain absolute child */
position: relative;
}
div.grid-content > div {
/* this is strategy for creating a container that adapts to the size of its relative parent using absolute positioning without the need of setting a fixed height to div.grid-content */
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* add scroll on y axis */
overflow-y: auto;
}
div.grid-content > div > div {
height: 200vh;
width: 50%;
background-color: #0000ff;
}
<div class="grid">
<div class="grid-header">
<h3>
hi
</h3>
</div>
<div class="grid-content">
<div>
<div>
asdf
</div>
</div>
</div>
<div class="grid-footer">
<h3>
bye
</h3>
</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With