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!

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
MrG
  • 5,277
  • 17
  • 48
  • 66

8 Answers8

272

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/

jackJoe
  • 11,078
  • 8
  • 49
  • 64
  • 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? – Mir Nov 30 '12 at 23:23
  • 2
    @Mir 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. – jackJoe Dec 01 '12 at 20:22
  • 6
    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. – Danny_Joris May 17 '13 at 19:59
  • @Danny_Joris 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. – jackJoe May 17 '13 at 20:14
  • 1
    @Danny_Joris I agree. Also, if you use media queries, it's difficult now to push the right column *below* the left column – andrewtweber Sep 03 '13 at 19:29
  • 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! – Guillaume Bois Nov 08 '13 at 20:05
  • 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. – ProVega Mar 17 '14 at 05:01
  • Is it possible to get the column heights to always be equal? See this demo, I would not like to see any red. http://jsfiddle.net/louiswalch/uEj55/92/ – Louis W Jun 03 '14 at 17:06
  • @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. – AturSams Jun 16 '14 at 11:42
  • 2
    For those who are curious about how it works, an explanation can be found here: http://stackoverflow.com/questions/25475822/why-does-css-float-not-change-the-width-of-the-following-div/25476238#25476238 – Hashem Qolami Oct 28 '14 at 06:11
  • 1
    I wonder if there is a way to have the right column AFTER the left, so that it properly stacks (without using flexbox) – Dominic Mar 10 '15 at 13:29
  • this way is not good for SEO, because content of the right column display first , which should be display later (after left column) – TomSawyer May 06 '15 at 09:01
  • 1
    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: http://codepen.io/martinkrulltott/pen/yNxezM – Martin Jul 21 '15 at 01:39
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;
Dave Koo
  • 463
  • 4
  • 12
Adam
  • 5,045
  • 1
  • 25
  • 31
  • 1
    Fantastic, simple solution and keeps the correct HTML order too! – user1794295 Jul 11 '14 at 15:16
  • 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! – Malabar Front Dec 01 '14 at 11:25
  • I like this solution because come mobile breakpoint time the right columns / sidebar will appear below not above the left column content. – dougtesting.net Apr 02 '17 at 00:50
  • i couldn't get the right column to go to the top with this method. – mulllhausen Feb 02 '18 at 12:24
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>
Loren
  • 1,273
  • 1
  • 12
  • 14
  • 1
    Great solution. Keeping the right below the left in HTML is crucial for layouts such as blogs, where the left has more important content. – Jake Jan 14 '14 at 21:00
  • 3
    Excellent answer! Here's a working example on Codepen: http://codepen.io/martinkrulltott/pen/yNxezM – Martin Jul 21 '15 at 01:40
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}
Benjamin Bouchet
  • 12,971
  • 2
  • 41
  • 73
  • 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.. – Dominic Mar 10 '15 at 13:39
  • 1
    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. – MarzSocks Jun 18 '16 at 14:33
  • That is unfair, because this solution is at least semantically correct and friendly towards simply RWD techniques, whilst using a `table` with `td`s most certainly is not! – ianp May 12 '17 at 15:41
  • 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. – AnthonyVO May 14 '18 at 11:52
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.

Illya Moskvin
  • 294
  • 1
  • 4
  • 15
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.

Community
  • 1
  • 1
Salman A
  • 262,204
  • 82
  • 430
  • 521
  • 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. – TomSawyer May 06 '15 at 09:00
  • have you ever tried to put more content and resize. just tested your code and didn't work. – TomSawyer May 07 '15 at 04:49
  • @TomSawyer I am not sure what you are talking about. Here is me trying to put more content: http://jsfiddle.net/salman/mva6cnxL/ and http://jsfiddle.net/salman/mva6cnxL/1/. Works flawlessly. – Salman A May 07 '15 at 06:18
  • Just what I searched for. Thanks –  Aug 05 '18 at 13:35
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.

-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>