The problem, is that I have a content div which stretches its container height-wise (container and content div have auto height).
I want the background container, which is a sibling div of the content div to stretch to fill the container. The background container contains divs to break the background into chunks.
The background and container divs have 100% width, the content container doesn't.
HTML:
<div id="container">
<div id="content">
Some long content here ..
</div>
<div id="backgroundContainer">
<div id="someDivToShowABackground"/>
<div id="someDivToShowAnotherBackground"/>
</div>
</div>
CSS:
#container {
height:auto;
width:100%;
}
#content {
height: auto;
width:500px;
margin-left:auto;
margin-right:auto;
}
#backgroundContainer {
height:100%;??? I want this to be the same height as container, but 100% makes it the height of the viewport.
}
In 2018 a lot of browsers support the Flexbox and Grid which are very powerful CSS display modes that overshine classical methods such as Faux Columns or Tabular Displays (which are treated later in this answer).
In order to implement this with the Grid, it is enough to specify display: grid and grid-template-columns on the container. The grid-template-columns depends on the number of columns you have, in this example I will use 3 columns, hence the property will look: grid-template-columns: auto auto auto, which basically means that each of the columns will have auto width.
Full working example with Grid:
html, body {
padding: 0;
margin: 0;
}
.grid-container {
display: grid;
grid-template-columns: auto auto auto;
width: 100%;
}
.grid-item {
padding: 20px;
}
.a {
background-color: DarkTurquoise;
}
.b {
background-color: LightSalmon;
}
.c {
background-color: LightSteelBlue;
}
<!DOCTYPE html>
<html>
<head>
<title>Three Columns with Grid</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="grid-container">
<div class="grid-item a">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas id sapien auctor, faucibus felis et, commodo magna. Sed eu molestie nibh, ac tincidunt turpis. Pellentesque accumsan nunc non arcu tincidunt auctor eget ut magna. In vel est egestas, ultricies dui a, gravida diam. Vivamus tempor facilisis lectus nec porta.</p>
</div>
<div class="grid-item b">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas id sapien auctor, faucibus felis et, commodo magna. Sed eu molestie nibh, ac tincidunt turpis. Pellentesque accumsan nunc non arcu tincidunt auctor eget ut magna. In vel est egestas, ultricies dui a, gravida diam. Vivamus tempor facilisis lectus nec porta. Donec commodo elit mattis, bibendum turpis eu, malesuada nunc. Vestibulum sit amet dui tincidunt, mattis nisl et, tincidunt eros. Vivamus eu ultrices sapien. Integer leo arcu, lobortis sed tellus in, euismod ultricies massa. Mauris gravida quis ligula nec dignissim. Proin elementum mattis fringilla. Donec id malesuada orci, eu aliquam ipsum. Vestibulum fermentum elementum egestas. Quisque sit amet tempor mi.</p>
</div>
<div class="grid-item c">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas id sapien auctor, faucibus felis et, commodo magna. Sed eu molestie nibh, ac tincidunt turpis.</p>
</div>
</div>
</body>
</html>
Another way would be to use the Flexbox by specifying display: flex on the container of the columns, and giving the columns a relevant width. In the example that I will be using, which is with 3 columns, you basically need to split 100% in 3, so it's 33.3333% (close enough, who cares about 0.00003333... which isn't visible anyway).
Full working example using Flexbox:
html, body {
padding: 0;
margin: 0;
}
.flex-container {
display: flex;
width: 100%;
}
.flex-column {
padding: 20px;
width: 33.3333%;
}
.a {
background-color: DarkTurquoise;
}
.b {
background-color: LightSalmon;
}
.c {
background-color: LightSteelBlue;
}
<!DOCTYPE html>
<html>
<head>
<title>Three Columns with Flexbox</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="flex-container">
<div class="flex-column a">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas id sapien auctor, faucibus felis et, commodo magna. Sed eu molestie nibh, ac tincidunt turpis. Pellentesque accumsan nunc non arcu tincidunt auctor eget ut magna. In vel est egestas, ultricies dui a, gravida diam. Vivamus tempor facilisis lectus nec porta.</p>
</div>
<div class="flex-column b">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas id sapien auctor, faucibus felis et, commodo magna. Sed eu molestie nibh, ac tincidunt turpis. Pellentesque accumsan nunc non arcu tincidunt auctor eget ut magna. In vel est egestas, ultricies dui a, gravida diam. Vivamus tempor facilisis lectus nec porta. Donec commodo elit mattis, bibendum turpis eu, malesuada nunc. Vestibulum sit amet dui tincidunt, mattis nisl et, tincidunt eros. Vivamus eu ultrices sapien. Integer leo arcu, lobortis sed tellus in, euismod ultricies massa. Mauris gravida quis ligula nec dignissim. Proin elementum mattis fringilla. Donec id malesuada orci, eu aliquam ipsum. Vestibulum fermentum elementum egestas. Quisque sit amet tempor mi.</p>
</div>
<div class="flex-column c">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas id sapien auctor, faucibus felis et, commodo magna. Sed eu molestie nibh, ac tincidunt turpis.</p>
</div>
</div>
</body>
</html>
The Flexbox and Grid are supported by all major browsers since 2017/2018, fact also confirmed by caniuse.com: Can I use grid, Can I use flex.
There are also a number of classical solutions, used before the age of Flexbox and Grid, like OneTrueLayout Technique, Faux Columns Technique, CSS Tabular Display Technique and there is also a Layering Technique.
I do not recommend using these methods for they have a hackish nature and are not so elegant in my opinion, but it is good to know them for academic reasons.
A solution for equally height-ed columns is the CSS Tabular Display Technique that means to use the display:table feature.
It works for Firefox 2+, Safari 3+, Opera 9+ and IE8.
The code for the CSS Tabular Display:
#container {
display: table;
background-color: #CCC;
margin: 0 auto;
}
.row {
display: table-row;
}
.col {
display: table-cell;
}
#col1 {
background-color: #0CC;
width: 200px;
}
#col2 {
background-color: #9F9;
width: 300px;
}
#col3 {
background-color: #699;
width: 200px;
}
<div id="container">
<div id="rowWraper" class="row">
<div id="col1" class="col">
Column 1<br />Lorem ipsum<br />ipsum lorem
</div>
<div id="col2" class="col">
Column 2<br />Eco cologna duo est!
</div>
<div id="col3" class="col">
Column 3
</div>
</div>
</div>
Even if there is a problem with the auto-expanding of the width of the table-cell it can be resolved easy by inserting another div withing the table-cell and giving it a fixed width. Anyway, the over-expanding of the width happens in the case of using extremely long words (which I doubt anyone would use a, let's say, 600px long word) or some div's who's width is greater than the table-cell's width.
The Faux Column Technique is the most popular classical solution to this problem, but it has some drawbacks such as, you have to resize the background tiled image if you want to resize the columns and it is also not an elegant solution.
The OneTrueLayout Technique consists of creating a padding-bottom of an extreme big height and cut it out by bringing the real border position to the "normal logical position" by applying a negative margin-bottom of the same huge value and hiding the extent created by the padding with overflow: hidden applied to the content wraper. A simplified example would be:
Working example:
.wraper {
overflow: hidden; /* This is important */
}
.floatLeft {
float: left;
}
.block {
padding-left: 20px;
padding-right: 20px;
padding-bottom: 30000px; /* This is important */
margin-bottom: -30000px; /* This is important */
width: 33.3333%;
box-sizing: border-box; /* This is so that the padding right and left does not affect the width */
}
.a {
background-color: DarkTurquoise;
}
.b {
background-color: LightSalmon;
}
.c {
background-color: LightSteelBlue;
}
<html>
<head>
<title>OneTrueLayout</title>
</head>
<body>
<div class="wraper">
<div class="block floatLeft a">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras malesuada ipsum pretium tellus condimentum aliquam. Donec eget tempor mi, a consequat enim. Mauris a massa id nisl sagittis iaculis.</p>
</div>
<div class="block floatLeft b">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras malesuada ipsum pretium tellus condimentum aliquam. Donec eget tempor mi, a consequat enim. Mauris a massa id nisl sagittis iaculis. Duis mattis diam vitae tellus ornare, nec vehicula elit luctus. In auctor urna ac ante bibendum, a gravida nunc hendrerit. Praesent sed pellentesque lorem. Nam neque ante, egestas ut felis vel, faucibus tincidunt risus. Maecenas egestas diam massa, id rutrum metus lobortis non. Sed quis tellus sed nulla efficitur pharetra. Fusce semper sapien neque. Donec egestas dolor magna, ut efficitur purus porttitor at. Mauris cursus, leo ac porta consectetur, eros quam aliquet erat, condimentum luctus sapien tellus vel ante. Vivamus vestibulum id lacus vel tristique.</p>
</div>
<div class="block floatLeft c">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras malesuada ipsum pretium tellus condimentum aliquam. Donec eget tempor mi, a consequat enim. Mauris a massa id nisl sagittis iaculis. Duis mattis diam vitae tellus ornare, nec vehicula elit luctus. In auctor urna ac ante bibendum, a gravida nunc hendrerit.</p>
</div>
</div>
</body>
</html>
The Layering Technique must be a very neat solution that involves absolute positioning of div's withing a main relative positioned wrapper div. It basically consists of a number of child divs and the main div. The main div has imperatively position: relative to it's css attribute collection. The children of this div are all imperatively position:absolute. The children must have top and bottom set to 0 and left-right dimensions set to accommodate the columns with each another. For example if we have two columns, one of width 100px and the other one of 200px, considering that we want the 100px in the left side and the 200px in the right side, the left column must have {left: 0; right: 200px} and the right column {left: 100px; right: 0;}
In my opinion the unimplemented 100% height within an automated height container is a major drawback and the W3C should consider revising this attribute (which since 2018 is solvable with Flexbox and Grid).
Other resources: link1, link2, link3, link4, link5 (important)
Make #container
to display:inline-block
#container {
height: auto;
width: 100%;
display: inline-block;
}
#content {
height: auto;
width: 500px;
margin-left: auto;
margin-right: auto;
}
#backgroundContainer {
height: 200px; /*200px is example, change to what you want*/
width: 100%;
}
Also see: W3Schools
Okay so someone is probably going to slap me for this answer, but I use jQuery to solve all my irritating problems and it turns out that I just used something today to fix a similar issue. Assuming you use jquery:
$("#content").sibling("#backgroundContainer").css("height",$("#content").outerHeight());
this is untested but I think you can see the concept here. Basically after it is loaded, you can get the height (outerHeight includes padding + borders, innerHeight for the content only). Hope that helps.
Here is how you bind it to the window resize event:
$(window).resize(function() {
$("#content").sibling("#backgroundContainer").css("height",$("#content").outerHeight());
});
Somewhere you will need to set a fixed height, instead of using auto everywhere. You will find that if you set a fixed height on your content and/or container, then using auto for things inside it will work.
Also, your boxes will still expand height-wise with more content in, even though you have set a height for it - so don't worry about that :)
#container {
height:500px;
min-height:500px;
}
You shouldn't have to set height: 100%
at any point if you want your container to fill the page. Chances are, your problem is rooted in the fact that you haven't cleared the floats in the container's children. There are quite a few ways to solve this problem, mainly adding overflow: hidden
to the container.
#container { overflow: hidden; }
Should be enough to solve whatever height problem you're having.
Just a quick note because I had a hard time with this.
By using #container { overflow: hidden; } the page I had started to have layout issues in Firefox and IE (when the zoom would go in and out the content would bounce in and out of the parent div).
The solution to this issue is to add a display: inline-block; to the same div with overflow:hidden;
I ended up making 2 display:table;
#container-tv { /* Tiled background */
display:table;
width:100%;
background-image: url(images/back.jpg);
background-repeat: repeat;
}
#container-body-background { /* center column but not 100% width */
display:table;
margin:0 auto;
background-image:url(images/middle-back.png);
background-repeat: repeat-y;
}
This made it have a tiled background image with a background image in the middle as a column. It stretches to 100% height of page not just 100% of browser window size
Try excluding height from the style element.
i.e. neither give height:100% nor to any other value.
{
height:100vh;
width:100vw;
}