Home Blog CV Projects Patterns Notes Book Colophon Search

Simple, Robust Layout with Float

10 Feb, 2013

2016: Updated with BEM and JSFiddle examples.

CSS grids are springing up everywhere, but laying out content in a cross-browser way with just float is incredibly easy, so before you pull another 50KB of CSS into your page, why not do it the easy way?

The two things you need to know for layout are that:

  1. You should use a block-level element (this means explicitly adding display: block to in the CSS)
  2. You need to add an element to clear the floats every time you want to start a new row

Let's start with a two column layout of primary and secondary content, and let's assume that since we'll want some padding and border, we use two divs for each as explained above:

<div class="main">
  <div class="main__content">
    <h1>Main Content</h1>
    <p>This is all very exciting stuff.</p>
  </div>
</div>
<div class="secondary">
  <div class="secondary__content">
    Links:
    <ul>
      <li><a href="">Link 1</a></li>
      <li><a href="">Link 2</a></li>
    </ul>
  </div>
</div>

You usually put the secondary content after the main content in the markup so that the main content loads first, and so that someone without CSS and JS (or with a screen reader) would read it first.

First some styles (nothing to do with the floating, just to make things pretty:

.main__content, .secondary__content {
    padding: 10px;
    margin: 10px;
    border: 1px solid #000;
}

Now for the layout:

.main {
    width: 75%;
}
.secondary {
    width: 25%;
}
.main, .secondary {
    float: left;
    display: block;
}

Update: I've created a JSfiddle. See it at https://jsfiddle.net/g3bdhppt/.

Now, let's say you want the main content on the other side. All you have to do is change the blocks to float right instead. Because the main content is first in the HTML, it will get to the right hand side first, and the secondary content will float behind it:

See jsfiddle at https://jsfiddle.net/g3bdhppt/1/

This all works with multiple columns too, just make sure the widths add up correctly to 100% and that you don't set any paddings, margins or borders on the divs you are floating (because that would affect the width calculations).

Now, what, if you want content before and after the floated content, but don't want to set the widths explicitly, and want the browser to just do its best, but keeping the columns in the right place?

Well, you can just remove the widths, but depending on what is before or after the blocks you are floating, the browser might try to put those on the same lines too. There are fancy techniques to try to prevent browsers doing this without adding any markup to the HTML, but none of them work in all browsers to my knowledge. Instead it is best to use a foolproof technique - put an element with an 100% width, zero height and an instruction not to clear anything either side of it anywhere where you want the browser to start a new row.

I like to do this with a <div> element because it prevents any other behaviours a browser might have for other elements taking effect. You could use a <hr> element instead. I tend to give it a class named clear like this:

.clear {
    height: 0px;
    clear: both;
    display: block;
}

Here's some markup with a header, footer and two columns (note we don't do anything special with the header or footer at all, they can be anything):

<div class="header">
  <div class="header__content">
    Header
  </div>
</div>
<div class="clear"></div>
...
<div class="clear"></div>
<div class="footer">
  <div class="footer__content">
    Footer
  </div>
</div>
.header, .footer {
    width: 100%;
}
.header__content, .footer__content {
    padding: 10px;
    margin: 10px;
    border: 1px solid #000;
}

Without the <div class="clear"></div> lines, this would all appear on one line. With it, eveything works great, you just need an element.

Here's the final full example with the columns floated left:

.clear {
    height: 0px;
    clear: both;
    display: block;
 }
.header, .footer {
    width: 100%;
}
.header__content, .footer__content {
    padding: 10px;
    margin: 10px;
    border: 1px solid #000;
}
.main, .secondary {
    float: left;
    display: block;
}
.main__content, .secondary__content {
    padding: 10px;
    margin: 10px;
    border: 1px solid #000;
}
<div class="header">
  <div class="header__content">
    Header
  </div>
</div>
<div class="clear"></div>
<div class="main">
  <div class="main__content">
    <h1>Main Content</h1>
    <p>This is all very exciting stuff.</p>
  </div>
</div>
<div class="secondary">
  <div class="secondary__content">
    Links:
    <ul>
      <li><a href="">Link 1</a></li>
      <li><a href="">Link 2</a></li>
    </ul>
  </div>
</div>
<div class="clear"></div>
<div class="footer">
  <div class="footer__content">
    Footer
  </div>
</div>

Here's the fiddle: https://jsfiddle.net/g3bdhppt/3/

All the margins and paddings are exaclty because they are the ones we set. You can change them all and it won't break the layout because we've kept widths separate from paddings, margins and borders.

The beauty is also that we haven't needed any wrapper divs or anything complex. This is all very robust to the point where you can nest layouts in other layouts. Have a look at this:

<div class="header">
  <div class="header__content">
    Header
  </div>
</div>
<div class="clear"></div>
<div class="main">
  <div class="main__content">
    <h1>Main Content</h1>
    <p>This is all very exciting stuff.</p>


    <div class="header">
      <div class="header__content">
        Nested Header
      </div>
    </div>
    <div class="clear"></div>
    <div class="main">
      <div class="main__content">
        <h1>Nested Main Content</h1>
        <p>This is all very exciting stuff.</p>
      </div>
    </div>
    <div class="secondary">
      <div class="secondary__content">
        Nested Links:
        <ul>
          <li><a href="">Link 1</a></li>
          <li><a href="">Link 2</a></li>
        </ul>
      </div>
    </div>
    <div class="clear"></div>
    <div class="footer">
      <div class="footer__content">
        Nested Footer
      </div>
    </div>


  </div>
</div>
<div class="secondary">
  <div class="secondary__content">
    Links:
    <ul>
      <li><a href="">Link 1</a></li>
      <li><a href="">Link 2</a></li>
    </ul>
  </div>
</div>
<div class="clear"></div>
<div class="footer">
  <div class="footer__content">
    Footer
  </div>
</div>

See the fiddle here: https://jsfiddle.net/g3bdhppt/4/. Note: You might need to make the browser wider to prevent the outer links from breaking when the width is too low (a behaviour you want, but that makes it harder to see the structure).

Even though there is a bit of extra markup, you don't need to be nudging grid columns to one side or the other, you can just set the margins and widths you want.

Of course, if you are doing something very complicated and responsive, the grid approach might be simpler. But my advice would be not to choose a grid just because you don't know how to do things the simple way.

Copyright James Gardner 1996-2020 All Rights Reserved. Admin.