Make nested div stretch to 100% of remaining container div height
I have a containter div, which I want to stretch to at least the entire height of the window. If there's a lot of content in the container div, I want it to stretch to more than the window's height. This works.
In the container div I have an image. After/below the image, I have a second div. I want this nested div to stretch vertically to fill the remaining space of the container div. This doesn't work.
I've tried to illustrate the problem in this image. I want the div to stretch in the way illustrated in the left side of the right image, not as it looks on the right side of the right image.
The following is my code. As you can see, in this code I don't even try to make the div under the image stretch vertically, as nothing has worked. "Height: 100%" doesn't do the trick, as I've defined "100%" to be the height of the window by default, in order to make the container div to stretch to at least the window's height.
Style:
* {
margin: 0; padding: 0;
}
body {
overflow-y: scroll;
overflow-x: hidden;
}
body, html {
height: 100%;
}
.container {
display: block;
overflow: auto;
min-height: 100%;
height: 100%;
height: auto;
}
.bottom {
width: 100%;
}
HTML:
<div class="container">
<img src="image.jpg" width="100%">
<div class="bottom">
LOREM IPSUM
</div>
</div>
I have spent way too much time trying to figure it out, but by George I've got it!
The "Eureka" moment was reading other questions where people were asking "how can I do it without using tables?" Because of course this layout is easy with tables. But that made me think of display:table
.
As this blog post nicely argues, using display:table
gives you table layouts without the nasty mark-up overhead as HTML table layouts, allowing you to have semantic code and different layouts for different media queries.
I did end up having to make one change to the mark-up: a wrapper <div>
around the image. Also, max/min heights are all weird when dealing with table displays: height
settings are treated as preferred heights given the constraints of parent and child elements. So setting a height of zero on a display:table-row
wrapper div made that row fit to the content image exactly. Setting a height of 100% on the content div made it nicely fill the space in between the image and the minimum height of the parent container.
Voila!
Condensing just the essential code:
Markup:
<div class="container">
<div class="wrapper">
<img src="http://placekitten.com/600/250" />
</div>
<div class="bottom" contentEditable="true">
</div>
CSS:
body {
overflow-y: scroll;
overflow-x: hidden;
}
body, html {
height: 100%;
}
.container {
display: table;
width: 100%
height: 100%; /* this will be treated as a Minimum!
It will stretch to fit content */
}
div.wrapper{
display:table-row;
height:0px; /* take as little as possible,
while still fitting content */
}
img {
display:table-cell;
width:100%; /*scale to fit*/
}
.bottom {
display:table-cell;
height:100%; /* take as much as possible */
}
Works in Firefox 25, Chrome 32, Opera 18 and IE10. Doesn't work in IE 8, but then what does? It doesn't look broken in IE8, it just doesn't stretch to fit.
If you can test it in Safari, IE9, or mobile browsers, leave a comment.
The non-javascript way is to use flexbox. How exactly depends on a lot of details, but you can play around at http://the-echoplex.net/flexyboxes/.
Polyfills do exists, but what exactly to use depends on which browsers you are targeting.
Flex boxes will be nice, when they are widely supported.
Even nicer would be a change in the spec so that if you specify min-height
on a parent, you can use percentage values for a child object's min-height
, instead of requiring that the parent height value has to be set explicitly for child height percentages to have any meaning. But I digress...
In the meantime, using "faux columns" can sort of get the effect you want. The concept is simple: you let the child div have an auto height, but then you paint the background of the parent such that it looks like the child div's background is continuing to the full height.
The example at that link does it with a background image, but you can use a background gradient if you don't mind sacrificing support for Safari and IE9-. (Remembering that lack of support just means not-quite-so-pretty, everything is functionally the same.)
Example here:
http://fiddle.jshell.net/y6ZwR/3/