For a 3-element (header, body, footer) column on a screen (100vh), I want the header to be fixed on top and footer at bottom, then body taking up all space in between (in-between space). Note that the header and footer can be any sizes as well (texts or images) so I can't fix their heights in advance.
The body size is unknown in advance, for example it can be the area showing emails. If the body size is less than the in-between space (just a few emails), it will take it all. If it is larger (many emails), it should take it all but not expand the page to push the footer all the way down to only be seen when scrolled to bottom. That is, I want each element to be an independent section fixed at top/middle/bottom, having the middle taking all in-between space regardless it is larger or smaller.
I have played around using Flexbox and Absolute positioning on Codepen.
There are some commented out items in the body to expand and contract the body.
For the flexbox body to take all space, I have flex: 1 1 auto
but when the body is larger than in-between space, flex-grow: 1
and flex-basis: auto
expands the body and pushes the footer down. I can't figure out how to get the body to expand to take up the in-between space but fixed at that height regardless of size.
The absolute-position version works here. Giving the body a height of whatever after header and footer and putting it right below the header. Making header and footer position: fixed; z-index: 2
fixes them at the top and bottom regardless of the body size. The problem here is that I am assigning some fixed heights to the header and footer but I want them to be un-fixed (auto). I want the layout header to be able to display texts (so maybe 30px high) or images (maybe 100px high).
Please advise. The only and only solution I can think of is to use JS to read the header and footer heights in the absolute-positioning version. But I would like to use pure CSS if possible.
CodePudding user response:
Here is a solution using only css:
.container-fluid {
height: 100vh;
overflow-x: hidden;
}
.col-12 {
display: flex;
flex-direction: column;
flex: 1;
}
.header {
position: sticky;
top: 0;
background: lightblue;
}
.body {
flex: 1 1 auto;
}
.footer {
position: sticky;
bottom: 0;
background: lightblue;
}
<main class="container-fluid p-0">
<main class="row h-100">
<section class="col-12">
<div class="header bg-info w-100">
<h1>Welcome to FMail (flexbox)</h1>
</div>
<div class="body bg-dark text-white p-0 w-100">
<h5>The main email box (should always occupy all space between header and footer)</h5>
<ul>
<li>Email 1</li>
<li>Email 2</li>
<li>Email 3</li>
<li>Email 4</li>
<li>Email 5</li>
<li>Email 6</li>
<li>Email 7</li>
<li>Email 8</li>
<li>Email 9</li>
<li>Email 10</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
<li>Email ...</li>
</div>
<div class="footer bg-info w-100">
<h5>I am the footer (should be fixed at bottom)</h5>
</div>
</section>
</main>
</main>