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
:
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.
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 :)
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):
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:
And finally, without background colour:
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!
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.
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:
<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><div></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...
<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.
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:
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: