Clarification 1: the number of child divs is not fixed.
Clarification 2: the content of each child must not change the child size.
Clarification 3: the height of each child is defined by their class.
Clarification 4: the solution cant use any tag other than div.
This is my first question on StackOverflow, I have been trying for a few days to perfectly divide a container vertically, that is, children must occupy all the parent space without overlap, there is no need to handle overflow but is expected to be hidden or scrollable. (Image) Fiddle.
#body {height:500px; text-align:center} /* assume height = 100% of body */
/* Some colors for visibility */
#body > div { box-shadow:inset 0px 0px 5px;}
.red { color: red; background:pink; }
.blue { color: blue; background:lightblue; }
.green { color: green; background:lightgreen; }
/* You are not allowed to modify the height of the parent */
.parent{ height:40%; width: 90%; overflow:hidden; margin:3%; border:dotted 3px;}
/* However you are free to modify anything else */
/* Naive Approach */
.child,.lastchild {overflow:auto;}
.child { height: 20%; }
.special { height: 30%; }
#example-1 > .lastchild { height:80%; } /* 100% -20% */
#example-2 > .lastchild { height:50%; } /* 100% -20% -30% */
<div id="body">
example-1
<div id="example-1" class="parent">
<div class="red child">child 1</div>
<div class="blue lastchild">child 2 (lastchild)</div>
</div>
example-2
<div id= "example-2"class="parent">
<div class="red child special">child 3</div>
<div class="blue child">child 4 <br> with scroll <br> and more <br> lines </div>
<div class="green lastchild">child 5 (lastchild)</div>
</div>
</div>
Sounds easy, right?... please keep reading.
Each container (.parent) will have a set height/width, but the exact amount will be unknown to you (I used the browser size to emulate this restriction in the fiddle).
Most .child have height:20%; however, some "special" children have height:30%; you have no control over how many of these special children exist (if they exist), This is why the naive approach won't work.
As for the expected solution, It may only involve CSS (no script is allowed) and must support all of these: Firefox(62+), Chrome(69+), Edge(42+) and IE(11+).
Some final notes:
- .lastchild is guaranteed to be the last child of their .parent
- You can assume there is always some height left for .lastchild
- You can assume every .parent has exactly one .lastchild and at least one other .child
- You will never have an element with both classes (.child and .lastchild are mutually exclusive)
- And you dont need to worry about mobile support.
What i have tried so far:
- .lastchild { position:absolute; bottom:0px; top:???;} bottom is correct, but top needs to be calculated anyway.
- .lastchild { position:relative; top:0px; bottom:???;} top is correct, but bottom works differently for relative divs
- The question may sound similar to the sticky footer problem, however the whole point of this question is that the lastchild height is not fixed.
- The question may sound similar to Equal Height Columns but it's a different problem.
- I dislike the use of tables for non-tabular data, but as an experiment i tried it out. It almost worked, however the table will try to fit all the content, thrus changing the size of the cells to fit the overflow and that won't do.
- A lot of questions in Stack Overflow address similar questions, however, almost none restrict the use of javascript, so most solutions out there only resize the div after the page is loaded, which as stated above is not an acceptable solution.
- Solutions that need to handle each browser differently will be frowned upon, but will be accepted if no other solution exists.
- The use of display:table or display:grid is perfectly fine and allowed for the answer as long as a fair explanation is given. (take into account that IE grids behave different than most browsers)
PD: I have 0 experience with display:flex but i am led to believe it contains the solution i have been looking for and this looks quite promising, i will make an update as soon as posible:
Fill remaining vertical space with CSS using display:flex
Last Update:
- I believe it would be more intuitive to use ".parent:last-child" instead of ".lastchild"
- As stated before i was looking for the proper way to set the height of that last element and flexbox solves it beautifully.