Prop-Clear: CSS min-height hack

So, the CSS style min-height isn't supported by MSIE 6.0 and earlier. Just another item on the growing pile of reasons to switch to a newer browser like Opera or Firefox.

Anyway, web designers aren't so lucky, since designs need to work in MSIE as well as the newer browsers, and sometimes min-height is exactly the property you need to use.

Below are three boxes using the min-height property, set to 50px:

box
box box box box box box box box box box box box box box box box box box

Most min-height hacks start off with the min-height property and build from there, using CSS selector bugs or layering elements to achieve the final effect. This hack uses a different strategy, fixing the problem in all browsers with just two extra HTML tags and a bit of reuseable CSS.

Important

I wrote this article in 2004, and the marketshare landscape has changed quite a bit since then. Nowdays, all visual browsers support the CSS min-height property, so you should never need to use this "hack".


Thanks to Addlepated for testing this for me on MSIE/Mac and Safari :)

The Hack

Below is an empty div tag which we want to have a minimum height of 50px.

<div>
  box
</div>

Boxes expand by default, so let's not touch the height or overflow properties. Instead we'd like a way to "prop" the box open at 50px high. One way to do this is to insert an element which is 50px high, forcing the box to stay at least that high. The trick is to protect the content from looking strange when you do this.

So let's add a prop. I like to give it the class "prop" just to remind me what it's actually doing. Add it right after the containing element opens so you're sure it reaches all the way from the top to the bottom of the box.

<style type="text/css">
  .prop {
    height:50px;
  }
</style>

...

<div>
  <div class="prop"></div>
  box
</div>

We don't want it to interfere with the content, so we'll float it all the way to the right and make it just 1px wide.

<style type="text/css">
  .prop {
    height:50px;
    float:right;
    width:1px;
  }
</style>

...

<div>
  <div class="prop"></div>
  box
</div>

So here's our three boxes again, minus the min-height property, with the prop included (background colour added to the prop for clarity):

box
box box box box box box box box box box box box box box box box box box

The examples above work in most browsers with the prop alone because the boxes are themselves floated. In normal use, the prop will extend beyond the bottom of the box because floated elements are partially removed from the flow of the document. I say "partially" because there is still a way we can use the floated element to determine how high the enclosing element should be. The way is to add the next part of this hack: something for our prop to push down on.

We add this with another div tag. I like to use the class "clear" for this one:

<style type="text/css">
  .prop {
    height:50px;
    float:right;
    width:1px;
  }

  .clear {
    clear:both;
    height:1px;
    overflow:hidden;
  }
</style>

...

<div>
  <div class="prop"></div>
  box
  <div class="clear"></div>
</div>

We need the overflow:hidden; style since MSIE refuses to automatically make div tags less than 1em high when in Standards Compatible mode. And thus, with background colour:

box
box box box box box box box box box box box box box box box box box box

And finally, without background colour:

box
box box box box box box box box box box box box box box box box box box

Voila! Perfect min-height emulation via the height of the prop. In addition to not using any browser bugs or selector quirks as hacks, both the HTML and CSS also validate!

Things to note:

The actual box is really 51px high because of the height of the "clear" div. If you need an exact pixel size, just decrease the height of the prop to account for this.

Also, since the "prop" div depends on the "clear" div being beneath it to push down on, by extension, this means this hack depends on the "clear" div being 100% of the width of the containing box. div tags expand to 100% by default so you shouldn't need to worry about this if you don't specify any CSS widths for elements in the content area. However, if you give a 100% width to any other child element of the content area, the "clear" div won't reach all the way across anymore and the hack will fail.

The solution? Either don't specify 100% widths for elements in the content area, or, if you really need something to stretch all the way across which won't stretch automatically (like a table, for example), use a width of 99% instead. This will prevent the prop from being pushed outside of the box.

Important

People have been linking to me and emailing me about this hack. Half say, "it works! Thanks!", while the other half says, "well, this hack didn't work for me." Most often the reason the hack doesn't work is because people are applying it as-is without any modification.

This hack is not a "bit of code which fixes the problem". Rather it is an idea, a method of propping and clearing which keeps boxes open to a height you want.

Essentially there are two "pieces" to the hack: The Prop and The Clear. Many people take the HTML and CSS off this page and use it directly, even when there may be existing pieces of the page already performing one of the two functions required. For instance...

One link to this page came from a forum where a user was trying to keep a column of boxes with a floated image from stacking to the right. See the problem below followed by the associated HTML and CSS:

  • The images in these items are floated to the left so the text of each item flows around them. The fix for the peekaboo bug will make this example look okay in MSIE, but broken in other browsers.
  • This is some short text in the second list item.
  • You'll see that the image in the third list item overlaps the image from the second. In fact, if your browser window is wide enough, the second image might even hop up beside the first image.
<style type="text/css">
  ul.example {
    list-style-type:none;
    margin:10px;
    padding:0px;
  }
  ul.example li {
    border:2px solid #ff5555;
    background-color:#ffdddd;
    padding:5px;
    margin-bottom:10px;
    height:1%; /* Fix for MSIE peekaboo bug */
  }
  ul.example li img {
    float:left;
    margin-right:5px;
  }
</style>

...

<ul class="example">
  <li>
    <img src="avatar1.png" alt="">
    The images in these items are floated to the left so
      the text of each item flows around them.
    The fix for the peekaboo bug will make this example
      look okay in MSIE, but broken in other browsers.
  </li>
  <li>
    <img src="avatar2.png" alt="">
    This is some short text in the second list item.
  </li>
  <li>
    <img src="avatar3.png" alt="">
    You'll see that the image in the third list item
      overlaps the image from the second.
    In fact, if your browser window is wide enough, the
      second image might even hop up beside the first image.
  </li>
</ul>

The solution, of course, is to add a min-height of some kind which keeps this from happening. So people search the web and come across this page, try putting in the code just like I have written, and find that it doesn't work or produces totally unexpected results. The user who found this hack and tried to use it on the above code gave up because they tried adding it exactly as I have written it.

Well, you're not supposed to add the code just as it is. You're supposed to take the idea and apply it to the elements of this hack you already have. :) In the example above, the first element of this hack already exists: The floated image is your Prop. You don't need the 1px floated <div> if you already have a floated element with the height you want.

In this case, all we need is the clearing <div> to place at the bottom of each list item. The floated images will perform the rest of the hack for us.

<style type="text/css">
  ul.example {
    list-style-type:none;
    margin:10px;
    padding:0px;
  }
  ul.example li {
    border:2px solid #ff5555;
    background-color:#ffdddd;
    padding:5px 5px 4px 5px;
    margin-bottom:10px;
    height:1%; /* Fix for MSIE peekaboo bug */
  }
  ul.example li img {
    float:left;
    margin-right:5px;
  }

  .clear {
    clear:both;
    height:1px;
    overflow:hidden;
  }
</style>

...

<ul class="example">
  <li>
    <img src="avatar1.png" alt="">
    The images in these items are floated to the left so
       the text of each item flows around them.
    <div class="clear"></div>
  </li>
  <li>
    <img src="avatar2.png" alt="">
    This is some short text in the second list item.
    <div class="clear"></div>
  </li>
  <li>
    <img src="avatar3.png" alt="">
    Now that we have the clearing <code>&lt;div&gt;</code>
      in place, the blocks should no longer overlap.
    Try widening your browser window to see that, indeed,
      the images will not slide up on each other.
    <div class="clear"></div>
  </li>
</ul>

Notice the change to the <li> padding to compensate for the 1px element along the bottom. The above code results in...

  • The images in these items are floated to the left so the text of each item flows around them.
  • This is some short text in the second list item.
  • Now that we have the clearing <div> in place, the blocks should no longer overlap. Try widening your browser window to see that, indeed, the images will not slide up on each other.

Using the hack on your webpages

You'll notice that the only defining CSS property which affects the minimum height this hack generates, is the height property in the prop class. To make the code truly reusable anywhere on your pages, lets extract this property.

<style type="text/css">
  .prop {
    float:right;
    width:1px;
  }

  .clear {
    clear:both;
    height:1px;
    overflow:hidden;
  }

  .min50px {
    height:50px;
  }
</style>

...

<div>
  <div class="prop min50px"></div>
  50px
  <div class="clear"></div>
</div>

We're now applying two classes to the prop <div>. Most browsers support multiple classes in this fashion.

Now to define any minimum height, all you need to do is create a class containing only a height property and apply it with the prop class.

<style type="text/css">
  .prop {
    float:right;
    width:1px;
  }

  .clear {
    clear:both;
    height:1px;
    overflow:hidden;
  }

  .min50px {
    height:50px;
  }

  .min100px {
    height:100px;
  }

  .min150px {
    height:150px;
  }
</style>

...

<div>
  <div class="prop min50px"></div>
  50px
  <div class="clear"></div>
</div>

<div>
  <div class="prop min100px"></div>
  100px
  <div class="clear"></div>
</div>

<div>
  <div class="prop min150px"></div>
  150px
  <div class="clear"></div>
</div>

And the result:

50px
100px
150px

As a final note, often the hack will be used as a way to apply a minimum height to an entire webpage, with a footer along the bottom. In this case, the footer can take the place of the clear <div>, merely by including the clear:both; property. If you're going to include content in this <div> then there's no need for the other two properties.

<style type="text/css">
  .prop {
    float:right;
    width:1px;
  }

  #menu {
    float:right;
    margin:0px;
    padding-left:1em;
    list-style:none;
    font:bold 90% Arial,sans-serif;
    text-align:left;
  }

  #footer {
    clear:both;
    border-top:2px solid #000000;
    text-align:left;
    font-size:80%;
  }

  .min200px {
    height:200px;
  }
</style>

...

<div>
  <div class="prop min200px"></div>
  <ul id="menu">
    <li>Home</li>
    <li>JavaScript</li>
    <li>PHP</li>
    <li>HTML/CSS</li>
  </ul>
  Webpage content
  <div id="footer">
    Copyright 2004 - GreyWyvern
  </div>
</div>

This is similar to the way I used the hack on my own website prior to its most recent redesign. The prop pushed down on the footer instead of an empty clearing <div>. The code above, which was actually quite similar to my own layout, will give you something like:

Webpage content