2 column div layout: right column with fixed width, left fluid
Asked Answered
F

8

164

My requirement is simple: 2 columns where the right one has a fixed size. Unfortunately I couldn't find a working solution, neither on stackoverflow nor in Google. Each solution described there fails if I implement in my own context. The current solution is:

div.container {
    position: fixed;
    float: left;
    top: 100px;
    width: 100%;
    clear: both;
}

#content {
    margin-right: 265px;
}

#right {
    float: right;
    width: 225px;
    margin-left: -225px;
}

#right, #content {
    height: 1%; /* fixed for IE, although doesn't seem to work */
    padding: 20px;
}
<div class="container">
    <div id="content">
        fooburg content
    </div>
    <div id="right">
        test right
    </div>
</div>

I get the following with above code:

|----------------------- -------|
| fooburg content  |            |
|-------------------------------|
|                  | test right | 
|----------------------- -------|

Please advise. Many thanks!

Fibriform answered 4/3, 2011 at 15:36 Comment(0)
G
273

Remove the float on the left column.

At the HTML code, the right column needs to come before the left one.

If the right has a float (and a width), and if the left column doesn't have a width and no float, it will be flexible :)

Also apply an overflow: hidden and some height (can be auto) to the outer div, so that it surrounds both inner divs.

Finally, at the left column, add a width: auto and overflow: hidden, this makes the left column independent from the right one (for example, if you resized the browser window, and the right column touched the left one, without these properties, the left column would run arround the right one, with this properties it remains in its space).

Example HTML:

<div class="container">
    <div class="right">
        right content fixed width
    </div>
    <div class="left">
        left content flexible width
    </div>
</div>

CSS:

.container {
   height: auto;
   overflow: hidden;
}

.right {
    width: 180px;
    float: right;
    background: #aafed6;
}

.left {
    float: none; /* not needed, just for clarification */
    background: #e8f6fe;
    /* the next props are meant to keep this block independent from the other floated one */
    width: auto;
    overflow: hidden;
}​​

Example here: http://jsfiddle.net/jackJoe/fxWg7/

Geithner answered 4/3, 2011 at 15:39 Comment(13)
This appears to be fragile if you try to put a clear: both anywhere in the left column. Is there a way around that, also? Or am I just trying to do things in a foolish way?Boost
@Boost A clear: both inside any of the columns won't affect the outside floats. This is not "fragile" unless you place the clear at the same level of the columns between the columns, if you place it at the end no harm is done.Geithner
I would consider using Adam's example. I don't think it's a good idea to put the right column before the left column in your html markup.Accessary
@Accessary It saved my bacon many times, besides, it allows you to style it to the left or the right and no need to remake the HTML markup.Geithner
@Accessary I agree. Also, if you use media queries, it's difficult now to push the right column below the left columnTorse
All the magic happens because of the overflow:hidden. This allow a fluid layout by avoiding to specify the fixed width of the floated column. The floated column then takes as much width as it needs to according to its content, then the non-floating columns takes up the rest. Wonderful!Hyde
Note: the "right" column has to be FIRST otherwise this won't work. Also if you are using borders, you will probably want a margin-right:WIDTHOFTHERIGHTCOLUMNHERE added to the left div.Arginine
Is it possible to get the column heights to always be equal? See this demo, I would not like to see any red. jsfiddle.net/louiswalch/uEj55/92Varner
@LouisW If that is what you want, you need to use the "faux column" technique which basically means a repeating background on their parent div.Jalopy
For those who are curious about how it works, an explanation can be found here: #25476322Parcel
I wonder if there is a way to have the right column AFTER the left, so that it properly stacks (without using flexbox)Brubaker
this way is not good for SEO, because content of the right column display first , which should be display later (after left column)Bonnet
As many people have pointed out, this is not a good solution since the right column is before the left column in the markup. The solutions posted below deals with this issue in a much better way, without using flexbox. Here's a working example: codepen.io/martinkrulltott/pen/yNxezMRozanne
A
73

See http://www.alistapart.com/articles/negativemargins/ , this is exactly what you need (example 4 there).

<div id="container">
    <div id="content">
        <h1>content</h1>
        <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.  Phasellus varius eleifend tellus. Suspendisse potenti. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nulla facilisi. Sed wisi lectus, placerat nec, mollis quis, posuere eget, arcu.</p>
        <p class="last">Donec euismod. Praesent mauris mi, adipiscing non, mollis eget, adipiscing ac, erat. Integer nonummy mauris sit amet metus. In adipiscing, ligula ultrices dictum vehicula, eros turpis lacinia libero, sed aliquet urna diam sed tellus. Etiam semper sapien eget metus.</p>
    </div>
</div>

<div id="sidebar">
    <h1>sidebar</h1>
    <ul>
        <li>link one</li>
        <li>link two</li>
    </ul>
</div>

#container {
    width: 100%;
    background: #f1f2ea url(background.gif) repeat-y right;
    float: left;
    margin-right: -200px;
}
#content {
    background: #f1f2ea;
    margin-right: 200px;
}
#sidebar {
    width: 200px;
    float: right;
Ake answered 4/3, 2011 at 15:40 Comment(4)
Fantastic, simple solution and keeps the correct HTML order too!Fraternize
I did not know about this. How did I not know about this. Perfect! I've been trying to do the whole 'fluid input, fixed-width search button', and obviously source order is really important here. This nails it. Thanks!Robers
I like this solution because come mobile breakpoint time the right columns / sidebar will appear below not above the left column content.Prolate
i couldn't get the right column to go to the top with this method.Dealing
P
29

Best to avoid placing the right column before the left, simply use a negative right-margin.

And be "responsive" by including an @media setting so the right column falls under the left on narrow screens.

<div style="background: #f1f2ea;">
  <div id="container">
    <div id="content">
        <strong>Column 1 - content</strong>
    </div>
  </div>
  <div id="sidebar">
    <strong>Column 2 - sidebar</strong>
  </div>
<div style="clear:both"></div>

<style type="text/css">
#container {
    margin-right: -300px;
    float:left;
    width:100%;
}
#content {
    margin-right: 320px; /* 20px added for center margin */
}
#sidebar {
    width:300px;
    float:left
}
@media (max-width: 480px) {
    #container {
        margin-right:0px;
        margin-bottom:20px;
    }
    #content {
        margin-right:0px;
        width:100%;
    }
    #sidebar {
        clear:left;
    }
}
</style>
Pneumatophore answered 4/3, 2011 at 15:36 Comment(2)
Great solution. Keeping the right below the left in HTML is crucial for layouts such as blogs, where the left has more important content.Weekday
Excellent answer! Here's a working example on Codepen: codepen.io/martinkrulltott/pen/yNxezMRozanne
J
13

Simplest and most flexible solution so far it to use table display:

HTML, left div comes first, right div comes second ... we read and write left to right, so it won't make any sense to place the divs right to left

<div class="container">
    <div class="left">
        left content flexible width
    </div>
    <div class="right">
        right content fixed width
    </div>
</div>

CSS:

.container {
  display: table;
  width: 100%;
}

.left {
  display: table-cell;
  width: (whatever you want: 100%, 150px, auto)
}​​

.right {
  display: table-cell;
  width: (whatever you want: 100%, 150px, auto)
}

Cases examples:

// One div is 150px fixed width ; the other takes the rest of the width
.left {width: 150px} .right {width: 100%}

// One div is auto to its inner width ; the other takes the rest of the width
.left {width: 100%} .right {width: auto}
Joeyjoffre answered 8/3, 2015 at 22:53 Comment(4)
Nice, worked well thanks. Sometimes there is a time and place for tables when flexbox is not a viable alternative. Rather than putting right content before in the DOM which doesn't stack properly..Brubaker
I like that this is a 'clean' solution. However, the only problem with putting your divs in table-cell mode is that you might as well use Tables & Tds. And you will end up loosing features like overflow scrolling etc.Yangyangtze
That is unfair, because this solution is at least semantically correct and friendly towards simply RWD techniques, whilst using a table with tds most certainly is not!Wineglass
This method easily allows for a media query to drop the Table for a regular divs if the columns get to narrow. Nice and clean. I like.Wilmott
P
6

I'd like to suggest a yet-unmentioned solution: use CSS3's calc() to mix % and px units. calc() has excellent support nowadays, and it allows for fast construction of quite complex layouts.

Here's a JSFiddle link for the code below.

HTML:

<div class="sidebar">
  sidebar fixed width
</div>
<div class="content">
  content flexible width
</div>

CSS:

.sidebar {
    width: 180px;
    float: right;
    background: green;
}

.content {
    width: calc(100% - 180px);
    background: orange;
}

And here's another JSFiddle demonstrating this concept applied to a more complex layout. I used SCSS here since its variables allow for flexible and self-descriptive code, but the layout can be easily re-created in pure CSS if having "hard-coded" values is not an issue.

Ponceau answered 22/12, 2015 at 3:46 Comment(0)
B
2

This is a generic, HTML source ordered solution where:

  • The first column in source order is fluid
  • The second column in source order is fixed
    • This column can be floated left or right using CSS

Fixed/Second Column on Right

#wrapper {
  margin-right: 200px;
}
#content {
  float: left;
  width: 100%;
  background-color: powderblue;
}
#sidebar {
  float: right;
  width: 200px;
  margin-right: -200px;
  background-color: palevioletred;
}
#cleared {
  clear: both;
}
<div id="wrapper">
  <div id="content">Column 1 (fluid)</div>
  <div id="sidebar">Column 2 (fixed)</div>
  <div id="cleared"></div>
</div>

Fixed/Second Column on Left

#wrapper {
  margin-left: 200px;
}
#content {
  float: right;
  width: 100%;
  background-color: powderblue;
}
#sidebar {
  float: left;
  width: 200px;
  margin-left: -200px;
  background-color: palevioletred;
}
#cleared {
  clear: both;
}
<div id="wrapper">
  <div id="content">Column 1 (fluid)</div>
  <div id="sidebar">Column 2 (fixed)</div>
  <div id="cleared"></div>
</div>

Alternate solution is to use display: table-cell; which results in equal height columns.

Barong answered 10/2, 2015 at 16:21 Comment(4)
second column on the right won't work. if the left column have full of text, your right column will display as a new row.Bonnet
have you ever tried to put more content and resize. just tested your code and didn't work.Bonnet
@Bonnet I am not sure what you are talking about. Here is me trying to put more content: jsfiddle.net/salman/mva6cnxL and jsfiddle.net/salman/mva6cnxL/1. Works flawlessly.Barong
Just what I searched for. ThanksBreathe
H
0

Hey, What you can do is apply a fixed width to both the containers and then use another div class where clear:both, like

div#left {

width: 600px;
float: left;
}

div#right {

width: 240px;
float: right;

}

div.clear {

clear:both;

}

place a the clear div under left and right container.

Humpback answered 4/3, 2011 at 15:48 Comment(0)
B
-3

I have simplified it : I have edited jackjoe's answer. The height auto etc not required I think.

CSS:

#container {
position: relative;
margin:0 auto;
width: 1000px;
background: #C63;
padding: 10px;
}

#leftCol {
background: #e8f6fe;
width: auto;
}

#rightCol {
float:right;
width:30%;
background: #aafed6;
}

.box {
position:relative;
clear:both;
background:#F39;
 }
</style>

HTML:

<div id="container">

  <div id="rightCol"> 
   <p>Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Phasellus varius eleifend. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Phasellus varius eleifend.</p>

  <p>Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Phasellus varius eleifend. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Phasellus varius eleifend.</p>
 </div>

 <div id="leftCol">

   <p>Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Phasellus varius eleifend. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Phasellus varius eleifend.</p>

  <p>Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Phasellus varius eleifend. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Phasellus varius eleifend.</p>
  <p>Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Phasellus varius eleifend. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Phasellus varius eleifend.</p>

Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Phasellus varius eleifend. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Phasellus varius eleifend.

</div>

</div>

<div class="box">
  <p>Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Phasellus varius eleifend. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Phasellus varius eleifend.</p>

  <p>Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Phasellus varius eleifend. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Phasellus varius eleifend.</p>
  <p>Lorem ipsum dolor sit amet,consectetuer adipiscing elit. Phasellus varius eleifend. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Phasellus varius eleifend.</p>
</div>
Bellhop answered 27/9, 2013 at 18:15 Comment(1)
Original question wants a right column with fixed size.Tugboat

© 2022 - 2024 — McMap. All rights reserved.