Three column layout with an auto-width center column - html

I'm trying to create 3 columns layout, where structure should be main, left column, right column. The main column is auto-width to fill rest of page.
Unfortunately I cannot change the HTML, which is currently like this:
<div class="wrap">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>
Yes: That means I cannot change the order of divs.
I've found some solutions, one of these is by using display: table-cell, but there is issue when using float. Second solutions is layout by using flexbox, it is pretty good solution, but I cannot use it because of IE9 where this CSS style isn't supported.
Just to restate the aim: My need is to have left and right with fixed width, and main will fill rest of free space.
<---250px--><----------------auto-width-------------><---200px--->
<---Left-----><------------------main------------------><---right----->
Have anyone any solutions for this in pure CSS without any JavaScript?

Here you go. A simple CSS solution. Remember you should always clear your floats.
HTML
<div class="left"></div>
<div class="right"></div>
<div class="main"></div>
<div class="clear"></div>
CSS
.main, .left, .right {
min-height: 250px;
}
.left {
float: left;
background-color: green;
width: 50px;
}
.right {
float: right;
background-color: blue;
width: 50px;
}
.clear {
clear: both;
}
.main {
background-color: gray;
}
JSFiddle: http://jsfiddle.net/18rvc23q/

You could try floating the sidebars to the left and right respectively, and then applying some padding to the .main div to keep it from overlapping them.
<style>
.left {float: left; width: 250px;}
.right {float: right; width: 200px;}
.main {padding: 0 200px 0 250px;}
</style>
<div class="wrap">
<div class="right">right</div>
<div class="left">left</div>
<div class="main">main</div>
</div>
https://jsfiddle.net/1ofqkLmw/
Note that in this markup I've moved the main div to be the last child of wrap.
Also note that you can just as well use margin instead of padding - if you don't want the border and background to overlap the sidebars, then margin is the way to go.

You could use a mix of left and right margin on .main and then absolute position the .left and .right columns.
HTML
<div class="wrap">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>
CSS
.wrap {
position: relative;
}
.main {
border: 1px dashed red;
margin: 0 100px;
min-height: 300px;
}
.left,
.right {
width: 100px;
min-height: 300px;
position: absolute;
top: 0;
}
.left {
left: 0;
background-color: yellow;
}
.right {
right: 0;
background-color: blue;
}
Here's a jsFiddle of it in action: http://jsfiddle.net/1u9gzyh6/

Two ways to do this:
HTML
<div class="wrap">
<div class="left"></div>
<div class="main"></div>
<div class="right"></div>
</div>
The better (but unsupported in IE9-) way
.wrap {
display:flex;
}
.left {
flex-basis:250px;
}
.right {
flex-basis:200px;
}
.main {
flex-grow:1;
}
The somewhat hackier, but supported in IE9 (but not IE8- or certain mobile browsers) way
.wrap {
display:block;
}
.left {
width:250px;
}
.right {
width:200px;
}
.main {
width:calc(100% - 450px);
}
UPDATE: if you wanted to dynamically add / remove columns, just add a few extra classes in your CSS file:
.main.no-left {
width:calc(100% - 200px);
}
.main.no-right {
width:calc(100% - 250px);
}
.main.no-left.no-right {
width:100%;
}
And apply the classes dynamically via JS as needed. Anything else requires a JS solution that actually sets the width as an inline style, or makes use of position:absolute;, which can get real hacky, real fast.

EDITED:
<style>
div {
margin: 0;
padding: 0
}
div.main-wrapper {
overflow: hidden;
width: 700px;
margin: 0 auto;
}
div.left-wrapper {
float: left;
width: 500px;
}
div.left-col {
float: left;
width: 200px; /*change to what value you desire*/
background-color: #5446EB;
height: 400px;
}
div.main-col {
background-color: #DDEB46;
height: 400px;
}
div.right-col {
float: right;
width: 200px; /*change to what value you desire*/
background-color: #EB838D;
height: 400px;
}
</style>
<div class="main-wrapper">
<div class="left-wrapper">
<div class="left-col">
insert content of the left col here
</div>
<div class="main-col">
insert content of the main col here.
</div>
</div>
<div class="right-col">
insert content of the right col here
</div>
</div>

I think this should solve your problem:
.main, .left, .right {
height: 250px;
}
.left {
float: left;
background-color: green;
width: 50px;
position: relative;
margin-left: -300px; // negative width of main
}
.right {
float: left;
background-color: blue;
width: 80px;
margin-left: 50px; // width of left
}
.main {
width: 300px;
background-color: gray;
float: left;
position: relative;
left: 50px; // width of left
}
.wrap:after {
content: "";
clear: both;
}
<div class="wrap">
<div class="main">Main</div>
<div class="left">Left</div>
<div class="right">Right</div>
</div>

Related

CSS: how to float two divs horizontally on the same line with consistent margin?

JSFiddle
HTML:
<div class="leftwrapper">
<div class="left">left div</div>
<div class="middle">middle div</div>
</div>
<div class="right">right div</div>
CSS:
.leftwrapper{
float: left;
width: 75%;
}
.left{
float:left;
background:green;
width: 30%;
max-width: 75px;
}
.middle{
background: blue;
overflow: hidden;
}
.right{
float: right;
background:red;
width: 30%;
max-width: 75px;
}
In the above example, I would like to:
Keep all three divs on the same line when resizing the browser (currently, the right div moves beneath the left),
Make it so the blue/middle div resizes to fill the space between left and right. As it stands, when you expand the browser the margin grows. How do you keep it consistent?
As a note: the structure of the HTML divs is intentional ('leftwrapper' containing two divs, floating alongside the right div), so please no answers involving restructuring of the divs!
I would add a flex parent, and use flex-grow to make the elements grow to fill the available space where you want that to happen.
.flex {
display: flex;
}
.grow {
flex-grow: 1;
}
.middle {
background: blue;
}
.left {
background: green;
width: 30%;
max-width: 75px;
}
.right {
background: red;
width: 30%;
max-width: 75px;
}
<div class="flex">
<div class="leftwrapper flex grow">
<div class="left">left div</div>
<div class="middle grow">middle div</div>
</div>
<div class="right">right div</div>
</div>
Change your CSS to this and it'll work nicely.
.leftwrapper {
float: left;
width: 100%;
max-width: calc(100% - 75px);
}
.middle {
background: blue;
overflow: hidden;
}
.left {
float: left;
background: green;
width: 30%;
max-width: 75px;
}
.right {
float: left;
background: red;
width: 30%;
max-width: 75px;
}
What I've done is change the width of .leftwrapper to 100% but added in a max-width property and used calc() to ensure it's also 75px smaller than 100% of the space it can fill up. That way resizing the viewport ensures it stays on one line nicely.
MDN information about calc().
#j.winslow I just updated the JSFIDDLE http://jsfiddle.net/enRkR/1232/
I add this:
.leftwrapper{
float: left;
width: 100%;
max-width: calc(100% - 75px);
}
This is what you're looking for? Regards!

Setting width to remainder width of parent element

I want to have a side nav of width: 150px; and then the content floating next to it. I want the content to be 100% minus the 150px side nav width. Is this possible?
I know I can do it in Javascript, but I would much rather know a simple CSS solution, something that would be:
width:100%-150px;
Is there such a solution?
I want the content to be 100% width, minus the 150px side nav width.
Is this possible?
Yes:
width: calc(100% - 150px);
N.B. Be sure to leave a space either side of the minus sign. The CSS parser needs to be clear it is parsing a minus sign, followed by a positive integer.
There are many different ways to achieve that, here are a few of them.
1. using float + overflow:
Note, the content box shouldn't set any float on it, and overflow:auto can prevent wrapped text going under the sidebar box.
.container:after {
content: "";
display: table;
clear: both;
}
.sidebar {
background: pink;
width: 150px;
float: left;
}
.content {
background: gold;
overflow: auto;
}
<div class="container">
<div class="sidebar">sidebar</div>
<div class="content">content</div>
</div>
2: using float + calc:
See the browser support tables - IE9+ basically.
.container:after {
content: "";
display: table;
clear: both;
}
.sidebar {
background: pink;
width: 150px;
float: left;
}
.content {
background: gold;
width: calc(100% - 150px);
float: left;
}
<div class="container">
<div class="sidebar">sidebar</div>
<div class="content">content</div>
</div>
3. using display:inline-block + calc:
.container {
font-size: 0; /*remove white space*/
}
.sidebar, .content {
font-size: 16px; /*reset font size*/
display: inline-block;
}
.sidebar {
background: pink;
width: 150px;
}
.content {
background: gold;
width: calc(100% - 150px);
}
<div class="container">
<div class="sidebar">sidebar</div>
<div class="content">content</div>
</div>
4. using CSS table:
.container {
display: table;
width: 100%;
}
.sidebar, .content {
display: table-cell;
}
.sidebar {
background: pink;
width: 150px;
}
.content {
background: gold;
}
<div class="container">
<div class="sidebar">sidebar</div>
<div class="content">content</div>
</div>
5. using flexbox:
See the browser support tables - IE10+ with prefixes.
.container {
display: flex;
}
.sidebar {
background: pink;
flex: 0 0 150px;
}
.content {
background: gold;
flex: 1;
}
<div class="container">
<div class="sidebar">sidebar</div>
<div class="content">content</div>
</div>
Another ways is to make the side nav float and then have the main content be width 100% and include a padding of 150px on the same side as the nav
An option would be to specify
.content {
left: 0;
position: absolute;
right: 150px;
}
.sidenav {
float: right;
margin-right: -150px;
}
instead of width: 100% for the content. Note: I assumed relative positioning on the parent element (which would contain both the content and side nav).
Good luck!

DIV width: auto is 0 pixel

I'm new in CSS and have not not found the solution for this basic problem. I have 3 divs in one line. The center div must have fixed width and it's position also fixed px from the center. I need auto width for the left and right div to fill the space at the left/right side. Here is my try but the left and right divs are zero width. Thanks for the help!
.fullwidth{
width:100%
height:20px;
}
.left{
background-color:green;
float:left;
height:20px;
width: auto;
}
.center{
background-color:red;
position:absolute;
right:50%;
margin-right:100px;
height:20px;
width:100px;
}
.right{
background:blue;
float:right;
height:20px;
width: auto;
}
<div class="fullwidth">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
What you're looking for is known as the flexible box model design, it is fairly new so there are some vendor prefix requirements although I have emitted them for simplicity. You may have noticed that there is poor support for Internet Explorer so if that's a concern you may need to look for alternatives. Regardless take a look of it in use:
.fullwidth {
width: 100%;
height: 20px;
display: flex;
}
.left {background-color: green;}
.center {
background-color: red;
width: 100px;
}
.right {background: blue;}
.left,.right {flex: 1;}
<div class="fullwidth">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
flexbox can do that.
Codepen Demo - Click "View Compiled" for all vendor prefixes
* {
box-sizing: border-box;
}
.fullwidth {
height: 20px;
display: flex;
}
.fullwidth .left,
.fullwidth .right {
flex: 1 0 auto;
}
.left {
background-color: green;
}
.center {
background-color: red;
flex: 0 0 100px;
margin-left: -100px;
}
.right {
background: blue;
}
.line {
/* center point reference for demo only */
position: absolute;
height: 50px;
left: 50%;
width: 1px;
border-right: 1px solid green;
}
<div class="fullwidth">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
<div class="line"></div>
You could use CSS calc function
.fullwidth {
width: 100%;
height: 20px;
}
.fullwidth div {
float: left
}
.left {
background-color: green;
height: 20px;
width: calc(50% - 50px);
}
.center {
background-color: red;
height: 20px;
width: 100px;
}
.right {
background: blue;
height: 20px;
width: calc(50% - 50px);
}
<div class="fullwidth">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>

Make a DIV vertically align in a middle

I have to make something like columns, but without table. This is example code:
<div class="main">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
<div class="endfloat"></div>
</div>
.left is on a left side, .center is in the middle and .right should be on a right side. But, .center should be also vertically aligned to the middle. Here is example and CSS example:
jsFiddle
Wrap the actual elements is a table-cell:
HTML
<div class="main">
<div class="table-cell">
<div class="left"></div>
</div>
<div class="table-cell">
<div class="center"></div>
</div>
<div class="table-cell">
<div class="right"></div>
</div>
</div>
SCSS
#mixin defaultDiv($bg, $height: 300px) {
width: 200px;
height: $height;
background-color: $bg;
display: table-cell;
}
.main {
outline: 1px solid red;
width: 600px;
display: table;
.table-cell {
display: table-cell;
width: 200px;
vertical-align: middle;
}
.left {
#include defaultDiv(green);
}
.center {
#include defaultDiv(blue, 200px);
}
.right {
#include defaultDiv(yellow, 250px);
}
}
JSFiddle demo: http://jsfiddle.net/3728vxa9/2/
Depending on if the height of the center element is in pixels or percent, you can place a div on top and below it. For instance, if it's height is 50 percent, place a div above and below it, each with a height of 25 percent.
HTML will look like this
<div class="main">
<div class="left"></div>
<div class="centerTop"></div>
<div class="center"></div>
<div class="centerBottom"></div>
<div class="right"></div>
<div class="endfloat"></div>
</div>
CSS will look like this
.centerTop {
height: 25%
}
.center {
height: 50%
}
.centerBottom {
height: 25%
}
Here are two examples of ways in which you could align a div in the middle:
Using HTML:
<div class="center" style="margin: 0 auto;"></div>
Styling in a separate CSS file:
.center { margin: 0 auto; }
If you are making three columns and want them to resize according to the window width, you set the value of their width to be 33%. Here is an example:
.center {
width: 33%;
}
.left {
width: 33%;
}
.right {
width: 33%;
}
Please see this link,
http://jsfiddle.net/n6t3qrux/
#mixin defaultDiv($bg, $height: 300px) {
float: left;
width: 200px;
height: 300px;
background-color: $bg;
}
.main {
outline: 1px solid red;
width: 600px;
height: 300px;
position: relative;
.left {
#include defaultDiv(green);
margin: auto;
position: absolute;
left: 0;
top: 0;
}
.center {
#include defaultDiv(blue, 200px);
margin: auto;
position: absolute;
left:0;
right: 0;
top: 0;
bottom: 0;
height: 200px;
}
.right {
#include defaultDiv(yellow, 250px);
margin: auto;
position: absolute;
right: 0;
top: 0;
}
.endfloat {
clear: both;
}
}
I wish this help you

How do I achieve this equidistant layout without calc?

Is there a "pure" way to achieve this layout where there is fixed content and equal fluid gutters, i.e. a way without using calc?
Fiddle
HTML:
<body>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
</body>
CSS:
body {
min-width: 300px;
}
.content {
width: 100px;
height: 100px;
background: blue;
float: left;
margin-left: calc((100% - 300px) / 4);
}
Unfortunately not. You could use a way to "almost" make it like that by using wrapper divs for each .content and style the wrappers to be one third of the body width. Within each wrapper you center the blue boxes. The drawback of that is the distance between the blue boxes is twice as wide as the distance from the outer blue boxes to the body border.
* {
margin: 0;
padding: 0;
border: 0;
}
body {
min-width: 300px;
width: 100%;
}
.content-wrapper {
width: 33.3333%;
text-align: center;
float: left;
}
.content {
width: 100px;
height: 100px;
background: blue;
margin: 0 auto;
}
<body>
<div class="content-wrapper"><div class="content"></div></div>
<div class="content-wrapper"><div class="content"></div></div>
<div class="content-wrapper"><div class="content"></div></div>
</body>
I fiddled around a bit and almost achieved a solution:
Fiddle
HTML:
<body>
<div id="wrap">
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
</div>
</body>
CSS:
body {
margin: 0;
}
#wrap {
text-align: justify;
}
.content {
width: 100px;
height: 100px;
background: blue;
display: inline-block;
}
#wrap:before {
content:"";
display: inline-block;
}
#wrap:after {
content:"";
width:100%;
display: inline-block;
}
If multiple pseudo-elements were possible, we could generate an empty inline-block (the same "empty word" as the :before) as :after(1) and the element with width:100% as :after(2).
Well, I couldn't get it to work. But thanks to you Paul for your answer and thanks chipChocolate.py and myfunkyside for the edit!