I have a single-column layout, where the body element acts as a column and has a distinctive background-color. I want the body element to fill the viewport height (currently using 100vh for this) so that inner elements can use height: 100%, but if the content of body is larger than the viewport, the body should grow (so that its background-color continues with the content).
Here's some demo code:
// This is just a helper code for the demo
// it's unrelated to the problem. Please, review the CSS block
let height = '';
document.querySelector('button').addEventListener('click', () => {
const newHeight = height === '' ? '2400px' : '';
height = newHeight;
const filler = document.querySelector('.content-filler')
filler.style.height = newHeight;
})
* {
box-sizing: border-box;
}
html {
background-color: white;
}
body {
width: 300px;
background-color: #b39ddb;
height: 100vh; /* fixed height is defined here */
padding: 0;
margin: 0;
margin-inline: auto;
}
.column {
height: 100%; /* this is inherited from the body's 100vh */
display: flex;
flex-direction: column;
}
.bottom-row {
margin-top: auto;
padding: 12px;
background: blueviolet;
}
.content-filler {
flex-shrink: 0;
background: #673ab7;
color: white;
padding: 8px;
}
<div class="column">
<div style="padding: 8px">
Hello world
<div>
<button>Toggle large content</button>
</div>
<br>
<div class="content-filler">Dynamic content</div>
</div>
<div class="bottom-row">bottom-row</div>
</div>
The problem with this implementation is that when you have content of large height, the body element stays fixed at 100vh and its background color appears to be "cut off".
Obviously this is expected for the fixed height value, but how can I solve this problem?
If I change height: 100vh to min-height: 100vh, then the child element's height: 100% would no longer take effect.
I tried using something like height: minmax(100vh, fit-content) for the height value, but unfortunately it didn't work.
Is there a way to solve this other then converting all elements in the tree to flex columns, starting from body?
UPDATE: One important use-case that I missed: further children of .column need to also be able to set height: 100%, and so on further down the tree.
I can't believe it, I think I solved it! Though feels more like winning a lottery of accidentally finding what works.
Use these styles for
body:I fiddled a lot with setting body to
flex, but it required updating all children to flex columns as well. But to my surprise,display: gridbehaves differently! In essence, it allows children of an element whose height is set bymin-heightto grow usingheight: 100%! And this is exactly what I was trying to achieve.Here's the updated demo:
So far I found only one issue: when my page is inside of an iframe, it has unwanted overscroll. Fortunately in my case I can control this and set
.is-iframeclass to body, for which I change the display value back toblock.I will play around some more and if I don't find serious issues I'll mark this as the answer