Div Expand to Visually Fill Vertical Space - html

I have a page that has a header, content, and footer. The header and footer are of fixed height, and I'd like the content to adjust its height so that it fits dynamically between the header and footer. I am planning to put a background-image in my content, so it is critical that it actually fills the rest of the unoccupied vertical space.
I used the Sticky Footer approach to ensure that the footer remains on the bottom of the page. This however does not make the content span the entire height of the remaining space.
I have tried several solutions which involved me adding height:100%, height:auto; position:relative but it did not work.
html,
body {
height: 100%;
background-color: yellow;
}
header {
width: 100%;
height: 150px;
background-color: blue;
}
header nav ul li {
display: inline;
padding: 0 30px 0 0;
float: left;
}
#wrapper {
min-height: 100%;
height: auto !important;
height: 100%;
margin: 0 0 -30px 0;
/* the bottom margin is the negative value of the footer's height */
position: relative;
}
#wrapper #content {
background-color: pink;
width: 400px;
height: 100%;
margin: 0 0 -30px 100px;
padding: 25px 30px 25px 30px;
}
footer {
margin: -30px 0 0 0;
width: 100%;
height: 30px;
background-color: green;
}
<div id="wrapper">
<header>
<div id="logo"></div>
<nav>
<ul>
<li>About</li>
<li>Menu</li>
<li>Specials</li>
</ul>
</nav>
</header>
<div id="content">
content
<br>goes
<br>here
</div>
</div>
<footer>footer</footer>

The trick about height:100% is that it requires all of the parent containers to be have their heights set as well. Here's an html example
<html>
<body>
<div id="container">
</div>
</body>
</html>
in order for the container div with a height set to 100% to expand dynamically to the height of the window you need to make sure that the body and html elements have their heights set to 100% as well. so...
html
{
height: 100%;
}
body
{
height: 100%;
}
#container
{
height: 100%;
}
would give you a container that expands to fit your window. then if you need to have footer or header that floats above this window you can do so with z indexing. This is the only solution I've found that fills the vertical height dynamically.

I'm providing a slightly more general solution so it is more useful for others reading this answer and wondering how to apply it to their site.
Assuming you have three divs:
<div id='header'></div>
<div id='contents'></div>
<div id='footer'></div>
where #header is fixed and may have variable height, #contents should consume all remaining vertical space and #footer is fixed and may have variable height you can do:
/* Note you could add a container div instead of using the body */
body {
display: flex;
flex-direction: column;
}
#header {
flex: none;
}
#contents {
flex: 1;
height: 100%;
overflow-y: scroll;
}
#footer {
flex: none;
}
Note that this will allow the contents to scroll vertically to show it's whole contents.
You can read more about display:flex here.

Try changing your css to this:
html,
body {
height: 100%;
background-color: yellow;
}
header {
width: 100%;
height: 150px;
background-color: blue;
}
header nav ul li {
display: inline;
padding: 0 30px 0 0;
float: left;
}
#wrapper {
min-height: 100%;
height: auto !important;
height: 100%;
margin: 0 0 -30px 0;
/* the bottom margin is the negative value of the footer's height */
position: relative;
}
#content {
background-color: pink;
width: 400px;
padding: 25px 30px 25px 30px;
position: absolute;
bottom: 30px;
top: 150px;
margin-left: 100px;
}
footer {
margin: -30px 0 0 0;
width: 100%;
height: 30px;
background-color: green;
}
<div id="wrapper">
<header>
<div id="logo"></div>
<nav>
<ul>
<li>About</li>
<li>Menu</li>
<li>Specials</li>
</ul>
</nav>
</header>
<div id="content">
content
<br>goes
<br>here
</div>
</div>
<footer>footer</footer>
You probably don't want to be setting the width, padding, margins, ect. of the wrapper. Also, with absolute positioning you can pull the bottom and top of the content to where you want them.
Here's what you are after, I think.

I spend several hours trying to figure this out too and finally have a robust solution without hacks. However, it requires CSS3, which requires a modern browser to support it. So, if this constraint works for you, then I have a real solution for you that works.
http://jsfiddle.net/u9xh4z74/
Copy this code into your own file if you need proof, as the JSFiddle will not actually render the flexbox correctly as embedded code.
Basically, you need to
- set the target container to 100% height, which you seem to already know
- the parent container you set display: flex and flex-direction: vertical (you'll see in the JSFiddle I've also included the alternate styles that do the same thing but are needed for cross browser support)
- you can let the header and footer be their natural heights and dont need to specify anything in that regard
- in the container you want to fill up the remaining space, set flex: 1. You're set! You'll see it works exactly as you semantically have intended. Also in the JSFiddle, I included overflow: auto to demonstrate that if you have even more text than the screen can handle, scrolling works as you would want it to.
<div style="display:flex; flex-direction:vertical;">
...header(s)...
<div style="flex: 1; overflow: auto;">
As much content as you want.
</div>
...footer(s)...
</div>
As a side note, I pursued the option of trying to do this same thing using display: table. It works just fine as well, except that overflowed content does not work as you would expect, instead overflowed content simply expands the container to the size of the content, which I'm pretty sure is not what you want. Enjoy!

Use display:table and display:table-row
Set height:0 for normal divs and height:auto for div that should fill vertical space. Insert a div with {height:100%; overflow-y:auto} into the vertical filler to if the containers height shouldn't expand beyond its preset height.
Behold the power of display:table!
<div style="height:300px;">
<div style="display:table; height:100%; width:100%;border: 1px solid blue;">
<div style="display: table-row; height:0; padding:2px; background-color:yellow;">
Hello
</div>
<div style="display: table-row; height:auto; padding:2px; background-color:green;">
<div style="height:100%; overflow: auto;">
<div style="height: 500px"></div>
</div>
</div>
<div style="display: table-row; height:0; padding:2px; background-color:yellow;">
Gbai
</div>
</div>
</div>

There is no 100% height from 100% continer height exactly. You can't solve it this way. Likewise while using mix of height + margin + padding. This is way straight to hell. I suggest you to take a look for tutorials which are sloving this page layout.

Related

CSS grow child to parent's max width

There are plenty of questions on how to make a parent's width that of it's child that are suggested as similar questions, this is not what I want.
I am working on theming a piece of software for branding purposes, I do not control the software and only have access to CSS modifications, so JavaScript or modifying the DOM is out of the question or this would be trivial.
Using CSS only, is it possible to achieve the following.
I have a container div that holds two columns, the main content area, and a sidebar. The sidebar contains multiple divs that wrap content for different sidebar elements. The content of these sidebar elements are designed to be scaled to 100% width of it's parent, which works when the parent has a fixed width, which is by default 25% of the container.
What we need is for the sidebar to disappear when it's content is hidden. The content within each sidebar element can be set to display: none, but when all the elements are hidden the sidebar still takes up empty space. The example below using a min-width: fit-content and a max width of the 25% which was previously it's fixed size, which works fine for hiding the sidebar when the content is hidden, but the content in the sidebar doesn't grow. Is there a way to make the content inside of .sidebarElementWrapper below, grow to fit the max-width of #sidebarArea
* {
margin: 0;
box-sizing: border-box;
}
#container {
height: 100%;
display: flex;
flex-direction: row;
}
#contentArea {
width: 100%;
background: #A84652;
}
#sidebarArea {
max-width: 25%;
min-width: fit-content;
background: #4262C2;
}
.sidebarElement {
width: 100%;
padding: 12px;
background: #8b8b8b;
border-bottom: 1px solid #2c2c2c;
}
<div id="container">
<div id="contentArea">
</div>
<div id="sidebarArea">
<div class="sidebarElementWrapper">
<div class="sidebarElement">Sidebar Element 1</div>
</div>
<div class="sidebarElementWrapper">
<div class="sidebarElement">Sidebar Element 2</div>
</div>
</div>
</div>
To hide the content of a sidebar element, the .sidebarElement is set to display: none, not the wrapper, just of note. Since the wrapper still exists, and the content isn't removed, just hidden, the :empty pseudo-selector also doesn't work.
Edit: Just to clarify as I don't think it was clear after reading through this again, when the content is hidden the sidebar should be gone, doesn't matter how whether it's through display:none or width or some other mechanism. When there is sidebar content it should be 25% the width of the container.
Edit again: Because of some comments, I'm going to attempt to explain this again.
The sidebar has a min and max width, it does not have a fixed width, the sidebar will scale to fit the content inside it. Because the sidebar does not have a fixed width, elements basing their width on 100% of the parent do not act like you may expect, instead the sidebar is defaulting to the min-width from what I can tell, which is the minimum width required to fit the content. I am not looking for this, I want the sidebar to extend out to 25% of the container width, which you can see if you copy this code into a file (because the snippet above will run in a smaller pane it may actually be wider than 25% so it may not be representative)
* {
margin: 0;
box-sizing: border-box;
}
body {
width: 100%;
height: 100%;
}
#container {
height: 100%;
display: flex;
flex-direction: row;
}
#contentArea {
width: 100%;
background: #A84652;
}
#sidebarArea {
max-width: 25%;
min-width: fit-content;
background: #4262C2;
}
.sidebarElement {
width: 100%;
padding: 12px;
background: #8b8b8b;
border-bottom: 1px solid #2c2c2c;
}
<div id="container">
<div id="contentArea">
</div>
<div id="sidebarArea">
<div class="sidebarElementWrapper">
<div class="sidebarElement">Sidebar Element 1</div>
</div>
<div class="sidebarElementWrapper">
<div class="sidebarElement">Sidebar Element 2</div>
</div>
</div>
</div>
In the end, I have a div with a min and max width, and a child element using a percent. The percent width (ie. width:100%) does not scale the child to the element's max width, but 100% of the current width, so no, the code as above does not achieve what I need.
I found a way to do it, fill-available.
.sidebarElement {
width: 100vw;
...
max-width: fill-available;
max-width: stretch;
max-width: -webkit-fill-available;
max-width: -moz-available;
}
Once this is done, the min-width on #sidebarArea can be removed.
* {
margin: 0;
box-sizing: border-box;
}
html,body {
width: 100%;
height: 100%;
}
#container {
height: 100%;
display: flex;
flex-direction: row;
}
#contentArea {
width: 100%;
background: #A84652;
}
#sidebarArea {
max-width: 25%;
background: #4262C2;
}
.sidebarElement {
width: 100vw;
padding: 12px;
background: #8b8b8b;
border-bottom: 1px solid #2c2c2c;
max-width: fill-available;
max-width: stretch;
max-width: -webkit-fill-available;
max-width: -moz-available;
}
<body>
<div id="container">
<div id="contentArea">
</div>
<div id="sidebarArea">
<div class="sidebarElementWrapper">
<div class="sidebarElement">Sidebar Element 1</div>
</div>
<div class="sidebarElementWrapper">
<div class="sidebarElement">Sidebar Element 2</div>
</div>
</div>
</div>
</body>

Combine fixed sidebar and fluid content with Push-Pull-Classes

In a Nutshell:
This is what i want to achieve: https://jsfiddle.net/Pintolus/faz88ayh/33 (you have to resize the result window to see the effect) but the #Content Div should fill out the rest of the screen-space next to the #Sidebar.
The Sidebar should still move UNDER the #Content on small screens.
This is what i want to achieve:
There should be 3 divs:
#Sidebar, which is on the left side and has a fixed width
#Content, which is on the right side and has a fluid width
#Footer, which is on the bottom of the page and is full width
That is not a big deal, but i want the #Sidebar to move under the #Content on small screens. This alone is also not a big deal and can be achieved by using Bootstraps Push- and Pull-Classes.
The problem is, that i have no idea how to combine both issues.
I want the sidebar to be fixed width (until it moves down) AND to move under the content-div.
This is the code for the left sidebar moving under the #Content:
HTML:
<div class="container-fluid">
<div class="row">
<div class="col-md-9 col-md-push-3" id="content"></div>
<div class="col-md-3 col-md-pull-9" id="sidebar"></div>
</div>
<div class="row"
<div id="footer"></div>
</div>
</div>
CSS: (Just for demo)
#sidebar {background: #CCC; height: 150px;}
#content {background: #111; height: 100px;}
#footer {background: #F00; height: 100px;}
See the fiddle here (You have to resize the results window).
Now i want the Sidebar in this fiddle to be fixed width (for example 100px).
Please help, this drives me crazy.
PS: position: absolute for the sidebar is no solution, because it will overlap the footer (due to different height).
Not sure how your push/pull works, bu I assume it's classes that appear on both your divs.
I wonder whether it would be easier to do that with media queries.
Anyway, here's a way to do it (sorry, my knowledge of bootstrap is close to nil, so I went for a very simplified piece of code):
http://jsfiddle.net/txLaukqm/1/
HTML :
<div id="sidebar"></div
><div id="content"></div>
<div id="footer"></div>
CSS:
html, body {
margin: 0;
padding: 0;
height: 100%;
}
body {
font-size: 0; /* to fight the space before the footer due to inline-block */
}
body * {
font-size: 1rem; /* to reset the font-size */
}
#sidebar {
display: inline-block;
background: #CCC;
height: calc(100% - 100px);
width: 100px;
vertical-align: top;
}
#sidebar.hidden {
display: none;
}
#content {
display: inline-block;
background: #111;
height: calc(100% - 100px);
width: calc(100% - 100px);
overflow: auto;
vertical-align: top;
}
#content.full-width {
width: 100%;
}
#footer {
background: #F00;
width: 100%;
height: 100px;
}

More than one image causing margin shift of whole page

I have tried everything I know, and I still can't get it to work. I want the four images to be like in the screen shot, but a lot bigger (600px centered). When I do this, however, it causes the entire container to be shifted to the left for some reason unknown to me.
HTML snippet:
<body>
<div class="container">
<div class="header">
..
</div>
<div class="menu">
...
</div>
<div class="content">
<div class="photos">
<h2> Here are some photos.....</h2>
<img src="img1">
<img src="img2">
...
</div>
</div>
</div>
</body>
CSS snippet:
body{
margin: 0;
padding: 0;
}
.container{
background-color: #AAC1CC;
max-width: 1440px;
width: 100%;
height: auto;
margin: 0 auto;
padding-bottom: 10px;
}
.content{
margin-left: 20px;
margin-bottom: 100px;
}
.photos {
background-color: pink; /* for testing */
width: 500px; /*for testing - normally 100% */
padding: 0;
margin: 0;
}
.photos img{
width: 100px;
display: block;
border: 2px solid black;
margin: auto;
margin-top: 40px;
margin-bottom: 40px;
box-shadow: 0 0 30px 3px #333;
}
Screenshot:
When the images are small (like 100px) the style is the same across the other tabs. However, if I increase the size of the images > 150px, the entire container shifts to the left by like ~20 pixels. I have tried using <br> between the images instead of display:block but it doesn't make a difference.
Why does this happen?
The only thing I can think of is that when the images are larger they cause the browser to display a scroll bar. As you have set the container width to 100% and the window width is now slightly smaller this could cause the shift that you mention.
I had a similar problem with a large image causing my main container to shift off center. threeandme's post reminded me to experiment with the overflow-y property in the css. I added overflow-y: scroll; into the css for "body" and it stopped it from shifting for me.

Create three divs such that the top and bottom ones have fixed height, and the middle one has dynamic height?

I want to create three, stacked divs. The top and the bottom ones will be of fixed height, whereas the one in the middle will have a dynamic height that expands to fill the remaining space:
I've tried numerous things, such as setting the height to auto. I do have a solution, but it involves JavaScript (i.e., calculating the remaining height) but I was wondering if there was a pure CSS solution.
There's a CSS solution, but it won't work in older browsers. You need to use the calc "function" that is new to CSS, combined with height: 100%. If you've never used height: 100% before, you know that every parent element of the one you want to be 100% tall must also be set to height:100%. calc can take a percentage value and subtract pixels from it, so you just need to set it to be 100% minus however tall the top and bottom divs are.
Supported by: IE9+, Firefox 4+, Chrome 19+, Safari 6+
http://caniuse.com/calc
HTML
<div id='top'></div>
<div id='mid'></div>
<div id='bot'></div>
CSS
html, body
{
height: 100%;
}
#top, #bot
{
height: 50px;
background: red;
}
#mid
{
height: calc(100% - 100px);
}
FIDDLE: http://jsfiddle.net/jakelauer/9cYUB/
One solution is to do it with position absolute.
The downside of this approach is that if the total height of surrounding is smaller then the sum of the fixed heights the container will not be visible anymore.
Another thing to be noted is that this is probably a bad solution if you want to target mobile devices. It always depends on the exact situation if this solution is suitable.
If i remember right you will only have problems with IE 6 (on desktop) which does not support the top bottom combination for the position absolute.
HTML
<div class="header"></div>
<div class="container"></div>
<div class="footer"></div>
CSS
.header, .container, .footer{
position: absolute;
outline: 1px solid black;
}
.header {
left: 0px;
top: 0px;
right : 0px;
height: 50px;
}
.container {
left: 0px;
top: 50px;
right : 0px;
bottom: 50px;
}
.footer {
left: 0px;
bottom: 0px;
right : 0px;
height: 50px;
}
JSFiddle
You can do it with a HTML table if you need older browser support, or if you need to support IE8+ or higher you could use the CSS table layout.
Here's a jsFiddle using CSS table layout.
HTML
<div>
<div>
<div>Fixed Height</div>
</div>
<div>
<div>
<div>Variable Height</div>
</div>
</div>
<div>
<div>Fixed Height</div>
</div>
</div>
CSS
html, body {
height:100%;
width: 100%;
margin: 0px;
padding: 0px;
text-align: center;
font-size: 20pt;
font-family: Verdana;
}
body > div {
display:table;
width: 100%;
height:100%;
}
body > div > div {
display: table-row;
}
body > div > div > div {
display: table-cell;
vertical-align: middle;
}
body > div > div:nth-child(odd) {
background: grey;
color: #FFF;
height: 100px;
}
body > div > div:nth-child(even) {
height:100%;
width:100%;
}
body > div > div:nth-child(even) >div {
height:100%;
width:100%;
overflow:hidden;
}
If i understand you request you need to use wrap div: http://www.cssstickyfooter.com/using-sticky-footer-code.html

div does not get centered using margin: auto in IE9

I am trying to get a centered in the space that is left empty by a sidebar. This is how I'd like it to look like:
I actually managed to make this work OK for most browsers using margin: auto for the div in question, while setting overflow: hidden:
Fiddle here
CSS
#header {
height: 50px;
background: #224444;
color: #fff;
}
#container div {
padding: 1em;
}
#content {
max-width: 400px;
margin: auto;
background: #ddd;
height: 300px;
overflow: hidden;
}
#sidebar {
float: right;
width: 200px;
background: #aaa;
height: 300px;
}
HTML
<div id="container">
<div id="header">
PAGE HEADER
</div>
<div id="sidebar">
Sidebar
</div>
<div id="content">
Centered Content
(Works everywhere but on IE9)
</div>
</div>
However, it does not work with IE9. It is strange as IE8 works OK!
I am running out of ideas, so I thought that maybe someone knows what is going on? The trick seems to work perfectly everywhere else.
NOTE: Please note that the content div should be flexible as it is in the demo. As the available space decreases, it should change size and squeeze in.
Isolate the centering from the floating
This affects IE9/10.
It works fine if the floated element is removed, or if width is used instead of max-width. The presence of floated content, combined with the use of margin:auto and max-width instead of width, appears to be confusing IE9+.
To fix this, put the centered content in a wrapper div, so that the centering of the content can be separated from the floating of the sidebar. In other words, too much is happening layout-wise in a single div, more than IE9+ can handle. So split up the #content div into two separate divs.
#header {
height: 50px;
padding: 1em;
background: #224444;
color: #fff;
}
#content-wrapper {
overflow: hidden;
}
#content {
max-width: 400px;
margin: auto;
padding: 1em;
background: #ddd;
height: 300px;
}
#sidebar {
float: right;
width: 200px;
padding: 1em;
background: #aaa;
height: 300px;
}
<div id="container">
<div id="header">
PAGE HEADER
</div>
<div id="sidebar">
Sidebar
</div>
<div id="content-wrapper">
<div id="content">
Centered Content
</div>
</div>
</div>
This tested fine in IE7/8/9/10. On a side note, because a wrapper div was added, the padding: 1em; now has to be added to each element individually.
IE is notorious for not working without proper doctypes.
Try adding the HTML5 one
<!DOCTYPE html>
Floats are a tricky business. Strictly speaking, they're only supposed to affect the inline content that flows around them, so margins acts like the floats aren't even there.
Try this instead:
#container {text-align:center}
#content {display:inline-block;text-align:left}
This should make the content box act like an inline element, and therefore appear centered in the space.
As far as I remeber I've always problems with margin:0 auto because I didn't specify width property.
So everytime you want use margin:auto you propably should write this:
#content {
max-width: 400px;
margin: auto;
background: #ddd;
height: 300px;
overflow: hidden;
width:500px;
}
or in percentage:
#content {
max-width: 400px;
margin: auto;
background: #ddd;
height: 300px;
overflow: hidden;
width:30%;
}
EDIT
If you want to create flexible layout please take a look to bootstrap and fluid grids.