pr0g33k

Clearing Containers with overflow: hidden

I recently completed a side-project where I needed to create two columns of text floated left and right. The text of each column was laid out in an unordered list and was dynamically generated using data from a database. This meant that one column could, at any point, be taller than the other column. This was fine until I wanted to place a vertical line separating the two columns. I could have used a border on the left or right of either unordered list but if one grew taller, the border of the other wouldn't grow with it. Then it hit me, why not use a background image in the container? Here's the markup and corresponding CSS:

<div class="columns">
    <div class="column1">
        <ul>
            <li>Column 1, Item 1</li>
            <li>Column 1, Item 2</li>
            <li>Column 1, Item 3</li>
            <li>Column 1, Item 4</li>
        </ul>
    </div>
    <div class="column2">
        <ul>
            <li>Column 2, Item 1</li>
            <li>Column 2, Item 2</li>
            <li>Column 2, Item 3</li>
            <li>Column 2, Item 4</li>
            <li>Column 2, Item 5</li>
            <li>Column 2, Item 6</li>
            <li>Column 2, Item 7</li>
            <li>Column 2, Item 8</li>
        </ul>
    </div>
</div>
    
<style>
    .columns {
        background: url(/images/vertical-line.png) repeat-y 50% 0;
        width: 402px;
    }

    .column1 {
        float: left;
        width: 200px;
    }

    .column2 {
        float: right;
        width: 200px;
    }
</style>
    

Unfortunately, this is what I got:

  • Column 1, Item 1
  • Column 1, Item 2
  • Column 1, Item 3
  • Column 1, Item 4
  • Column 2, Item 1
  • Column 2, Item 2
  • Column 2, Item 3
  • Column 2, Item 4
  • Column 2, Item 5
  • Column 2, Item 6
  • Column 2, Item 7
  • Column 2, Item 8

Where's my background image? It turns out that a container of floated elements does not automatically clear the floats of its child elements. The container instead assumes its default height (0px in the case of  a div) or whatever height it is assigned. I don't want to assign a height in this case, though; I want the container to size to the height of whichever child is tallest.

The solution is to set the overflow to hidden on the container. If I change the CSS to this:

    <style>
        .columns {
            background: url(/images/vertical-line.png) repeat-y 50% 0;
            overflow: hidden;
            width: 402px;
        }

        .column1 {
            float: left;
            width: 200px;
        }

        .column2 {
            float: right;
            width: 200px;
        }
    </style>
    

Then this is what I get:

  • Column 1, Item 1
  • Column 1, Item 2
  • Column 1, Item 3
  • Column 1, Item 4
  • Column 2, Item 1
  • Column 2, Item 2
  • Column 2, Item 3
  • Column 2, Item 4
  • Column 2, Item 5
  • Column 2, Item 6
  • Column 2, Item 7
  • Column 2, Item 8

It also means that I don't have to follow the container with an element assigned "clear: both" to clear the preceding floats.

Posted on 7/23/2013 at 02:07 PM , Edited on 7/23/2013 at 02:07 PM
Tags: HTML5CSS

Comments:

  1. Mandm

    You've got to be kidding me-it's so clear now!
  2. Maki

    I was seriously at DefCon 5 until I saw this post.
Leave a comment
  1. CAPTCHA