min-height: fixed;
September 16, 2004After one too many times wistfully wishing I could scale fixed-size elements according to their content in a cross-browser friendly way, I did something about it. Presenting min-height, without the min-height.
If I had a penny for every time I’ve run into a situation where I really needed a block of content with a specific height, but decided not to due to the issues involved… well, I’d have a few bucks anyway.
There’s no reliable way to place elements inside a parent and then have it expand gracefully along with the elements, if the parent has a starting height value. This is precisely the problem min-height solves, but it’s frustrating that it’s so unusable.
The Test Case
Take this demo page, for example. Placing the navigation where it is requires a header of an exact height, otherwise the proportions matching the photo and the rest of the header are completely off.
But if the list of nav items grows, or the user has a larger font size, or anything at all happens that would require the nav’s height to expand, it expands outside of the header and overlaps into the content area below within browsers that adhere to the spec for height property.
The Problem
min-height is the logical choice for finding a solution that would allow the header to expand gracefully as the nav does, but it isn’t supported by Internet Explorer or, unfortunately, Safari.
I say unfortunately because there’s a fantastically easy way around the issue in IE, but not Safari — height is basically treated as min-height. With a bit of filtering, it’s a snap to craft a solution that works between IE and Mozilla. But once you throw Safari in the mix, it’s not that simple.
Since min-height itself is unusable, there have only been a few possible ways of dealing with situations like this. Take this example page with four stacked, variable-sized divs. The content itself dictates the height of each, which may be fine for most purposes. But like the graphical example above, sometimes it makes more sense visually for the content to fit within a certain-sized area.
Let’s say the divs should be a minimum of 200px high. If we apply a height attribute directly to each, well, the results aren’t quite what we’d hope — scroll to the third & fourth divs to see them overlapping.
The problem is evident in anything but IE; the results are in fact exactly what we’re hoping for in IE, just not actually correct according to the spec. When we’re also trying to account for dynamic content (which could be any length) or scalable text (which could be any size), it’s even harder to predict a box’s optimal height. Defining specific heights will lead to overlap sooner or later, and that’s no good.
Potential Solutions
We could try overflow: auto; and force scrollbars to avoid it in all situations, but that’s a really kludgy workaround and no one likes scrollbars anyway. It’s a technical fix to a technical problem that affects the design adversely. No good.
We might be able to script our way around the problem (or use a proprietary attribute like IE’s expression property), but for the sake of validation and not relying on an external script, what about a fix using valid CSS alone?
Well, that pretty much exhausts the range of possibility. Or so I always believed.
I keep running into this problem in my own work, and I’m always unsatisfied by the eventual results. Letting the content dictate minimum size messes up proportions unless everyone and their dog is using the same default font size, which they’re not, and it forces limitations on how much content you can place inside the block which, given the required flexibility of most web design tasks these days, is never a good idea.
I finally got fed up with this limitation and decided it was time to fix it once and for all. And by George I think that’s exactly what I’ve done.
Solving It
My method of attack involved figuring out how to duplicate 200px of min-height without actually using min-height. I could see only one real way of going about it — I needed to prop open the parent element with some sort of 200px high spacer that wouldn’t affect the internal layout (and thus allow the element to expand as the content does, but not collapse past 200px if the content is short).
So I tried a few things and spent a while thinking about it, and here’s what ended up working. Take this construct:
<div class="box">
<p>Lorem ipsum dolor sit amet.</p>
</div>
Applying 200px of top padding to the parent div guaranteed it would always be at least 200px high — that’s half the battle right there.
.box {
padding-top: 200px;
}
The child p element is pushed down below that initial gap, so moving it back up to the top of the parent became the new challenge. Relative positioning would work, but it would also leave a space for the element. The total height of the construct would be child height + 200px, no matter what size the child was. No good.
Instead, a negative top margin of 200px would effectively erase that initial lead, and allow the entire construct to size according to the child… except when the child was smaller than 200px. Then the containing parent’s bottom edge would determine the size of the construct, which would always be 200px, which is our desired min-height effect.
.box {
padding-top: 200px;
}
.box p {
margin-top: -200px;
}
In Safari and Firefox, we’ve got it solved, but not IE. Remember that IE already does min-height though, because that’s how it treats height, so a bit of browser-specific filtering should do it:
/* for Mozilla/Safari */
*>.box {
padding-top: 200px;
}
*>.box p {
margin-top: -200px;
}
/* for IE */
* html .box {
height: 200px;
}
The problem is now IE5/Mac — it actually applies all three styles. It gets the first two right, but then it also has the same parsing bug that IE/Win does and applies the second one, which really makes a mess of things. So an extra filter for IE5/Mac is necessary:
/* for Mozilla/Safari */
*>.box {
padding-top: 200px;
}
*>.box p {
margin-top: -200px;
}
/* for IE, with IE5/Mac backslash filter \*/
* html .box {
height: 200px;
}
/* end filter */
Is that it? Not quite yet, there’s also Opera. Unfortunately it doesn’t want to seem to keep our containing box open; it looks like the lack of an explicit height value collapses the entire parent element, padding included. We can keep it open and get our padding back by setting a min-height, though… any value will do:
/* for Mozilla/Safari/Opera */
*>.box {
padding-top: 200px;
min-height: 1px;
}
*>.box p {
margin-top: -200px;
}
/* for IE, with IE5/Mac backslash filter \*/
* html .box {
height: 200px;
}
/* end filter */
Final Notes
And there we have it. (Also, a fully-commented version) It’s a bit messy, but it works in everything, and presumably it applies equally to the min-width property (although I haven’t tested that yet). The only caveat seems to be Opera 6, which despite all that still collapses the parent. Oh well, Opera 6 is two years old now and Opera users ought to know better than that, so I’m not losing sleep; it degrades gracefully, anyway, and that’s what’s important.
The only real markup dependency is on a parent that contains a single child. The construct used in the example has a single p element; adding a second one would mess things up considerably though, so in cases where more elements are needed within the parent it’s a better idea to add a secondary wrapper div as the child.
And our example from above? Piece of cake. When the navigation is longer, the content bumps down to account for the larger header. When it’s short, the header retains its minimum height.
Addendum: In theory, this should also work the same as the above method, but the syntax is a bit nicer. I’ll test it more thoroughly, so for now there are no guarantees about the utility of this code. (Thanks to Henrik Lied for pointing out !important, which I always manage to forget about)
.box {
padding-top: 200px !important;
height: auto !important;
height: 200px;
min-height: 1px;
}
*>.box p {
margin-top: -200px;
}
12/2/04 Addendum: maybe not. Faruk Ates reports the second example doesn’t work in IE. However, Mitchell Stokely provides this further variation based on his Stokely hack which remains unverified and untested at the moment:
/*IE 6 and Safari Hack*/
/*read by Mozilla 1.0-1.4,IE6,Safari*/
html*.box{
[height:100%;/*necessary to hide from Mozilla*/
height:100%;/*read by Safari*/
]height:100%;/*only read by IE6*/
}
.dummyend[id]{clear: both;
/*end hack using dummy attribute selector for IE5 mac*/}



Dave,
I was thinking about this exact problem yesterday, great timing on publishing the solution. I was also telling one of the progs at work about the emerging habit of calling these css tricks filters instead of hacks. Amusing that you used that wording in your post.
For those who still want to fall back to tables I can only urge you to open up a table based site on a pda or mobile phone. I was doing exactly that today when a new pda got delivered to the office. Even without pda specific style sheets css based sites were far more useable than table based sites. The first steps away from tables are hard (at least they were for me) but ultimately worth it. But you’ve all heard that before.
Great tip! I’m with some of the others that are confused by the resistance to “hacks.” Seems to me that this is just working within the bounds created by the browsers that are out there. Delivering the specific code that each browser requires to render the page properly (all browsers at the same time no less while still validating!) isn’t hacking…it’s just damn good coding and a ton of creativity.
Jeff -
Well, that element will remain 200px tall even if the content isn’t.
You also need min-height: 200px for standard-compliant browsers.
Sorry for the double-post.
I put together an example for you
http://dev.misinterpreted.net/min-height/
What’s wrong with Anne’s way?
http://annevankesteren.nl/archives/2004/04/min-height-in-safari
Great solution Dave!
And as for the CSS vs ..
Tables may give you a quick solution for THIS layout but they can add work if you need to do a redesign. I find it is always best to go with a logical document structure and then style to accommodate the design. Dave’s solution adds another tool in the box to add “table-like” styling of elements without adding the structure of a table to your HTML. You can re-style a span or a div but a table is a table.
“What’s wrong with Anne’s way?”
Well, mainly awareness — that’s the first time I’ve seen it.
But digging into it a bit, it doesn’t actually seem to work the same way min-height does. I replaced my hack-ish code in the demo page with the table-cell property Anne suggests, and while it does appear to influence the elements below as would be expected, the height acts as a hard cut-off point for the background image. Easy just to see it for yourself - http://www.mezzoblue.com/tests/minheight/index-anne.html - Also, IE5/Mac goes funky.
Too bad, otherwise it would have been a nice elegant fix to the problem.
As you said, a little messy, but we can’t have everything!
I’m just wondering the possibilities… hummmm
Thanx a lot!
Nice work. Wish you’d done this about a year ago. I went nuts trying to get Sarafi to do something with min-height and finally gave up. I might give this a shot. Incidentally, I feel the same way about Opera 6 - its a pain to work with.
You, sir, are an absolute life-saver. Magnificent!
Why not just resolve this issue in the browser that has a problem with it?
height:expression(this.scrollHeight < 200? “200px” : “auto” );
This code is pulled from Svend Tofte’s excellent article:
http://www.svendtofte.com/code/max_width_in_ie/
works specifically in IE only… perfect for resolving these kinds of IE only bugs.
Forgot to mention that the code would have to be reworked for the current block level element isntead of the browser itself. So:
p height:expression(“200px”);
Wouldn’t that work just the same?
Great coding skills !
Still I hesitate using your solution as it leaves me wondering all these hacks/filters will blow up in my face one day, when the next version of IE will start ignoring one or more hacks/filters.
Nick, read the article.
IE isn’t the only browser that has a problem, and of this more compact version of the code:
.box {width: 200px; margin: 0; padding: 0;}
*>.box {padding-top: 200px; min-height: 1px;}
*>.box p {margin-top: -200px;}
* html .box {
/* IE5Mac filter \*/
height: 200px;
/* end filter */
}
Only the very last of the four style rules is about IE. Using an expression invalidates your CSS, and still doesn’t account for Safari. This is all in the article.
I was dealing with the min-height problem myself only a few days ago, and came up with a similar solution, which is documented here:
http://www.brainsideout.com/weblog/archives/001288.php
It isn’t as sophisticated as your approach, and flubs (but degrades ever so gracefully) min-heights in IE5/Mac and Safari, but my intents and purposes were a bit different.
Thanks Dave, for not only figuring this magic out, but taking the time to share it with the rest of us.
Wim: “Still I hesitate using your solution as it leaves me wondering all these hacks/filters will blow up in my face one day, when the next version of IE will start ignoring one or more hacks/filters.”
That’s a classic argument against CSS hacks, to which my response has always been that you’re hedging your bets against an unknown that may or may not ever happen. I’d happily use a solution that doesn’t involve hacks/filters if one existed, but I’d more happily use this min-height variant now, today, when all browsers are known.
If it’s a problem in 5 years when IE7 is finally released, well, I’ll deal with it then. Chances are good enough that so many sites will use hacks in the next half decade that, to support existing sites, IE7 is going to have to fix ALL or NONE. Can you imagine the developer outcry if it breaks a bunch of standards-compliant sites? So I’m really, really, really not worried about it.
Dave, I was simply pointing out an example of how this could be done exclusivly for one browser with *supported* code (though non-standard)… instead of using hacks and work-arounds as so many others pointed out that these could come back to bite us if and when browser manufactures start fixing these bugs.
This is a perfect example where the upsides in design are outweighed by the downside in technology. If having to make this choice, I’d change the design, or *gasp* turn to tables.
This kind of per-browser hacking is just not worth it! If I feel bad creating a site with tables, I’d feel equally bad to create it with a .CSS file full of such hacks.
YMMV, though.
Well, there’s an even easier way.
Use the power of !important.
#box {
height: auto !important; /* This counts for standard-compliant browsers*/
height: 300px; /* Silly-Billy Internet Explorer */
}
While I may not need this trick right now, it certainly is a welcome addition to my toolbox. Thanks, man.
Henrik-
That works in most situations, but what if the element’s content is less than 300px tall?
Ah ha! Very Clever, Mr. Shea!
I have to agree with Gabriel on this one, its an innovative workaround, but id rather sneak a simple table in there, or live without it for time being… the box model hack ill give into but until then im praying to the browser gods for solid CSS support in the future.
Very nice, but a little too much hacking for me. There has to be another way….
Dave, I could kiss you! Or, um, maybe you’d prefer I buy you a beer next time I see you. I’ve been strugglig with this very issue - I’d got close, but always had at least one browser angry with me. This will almost immediately go into use on 3 sites I’m in the middle of developing.
Another day, another hack. It’s really to bad, but hey if it works that’s all that matters! I’ll probably use it and thanks, Dave, for all the brainpower on this one.
<<The (min-height) problem is evident in anything but IE; the results are in fact exactly what we’re hoping for in IE, just not actually correct according to the spec.>>
Come to think of it, nearly any design problem I want solved, IE6 is usually the first browser that renders my valid CSS “solution” correctly. Granted, I don’t use IE6 much anymore except to test, but as a CSS newbie trying to walk the web standards path, I find this maddening. Sigh, I can see why a lot of people don’t give a poobah about standards. Yet.
That’s a lot of work just to avoid using tables.
The standards propoganda crew are doing a fantastic job. Tables are still standards compliant you know.
My way around this problem has always been to insert a one-pixel wide empty div adjacent to the navigation, float it right or left, give it a height equal to your desired min-height, clear it, and then call it a day. That way, you eliminate min-height madness altogether.
Works in all browsers, takes very little time, but is obviously less semantically pure than your pure CSS solution.
This might be a time when a sly layout table is a good idea. Maybe.
But, what’s the harm in Dave (or anyone else) trying to figure out a CSS-only solution? How is this “propaganda?” The CSS soltuion is more accessible and renders better in a text-only browser or alternative device. This might not matter to you, but what’s wrong with Dave (or anyone else) placing value on this?
It’s fine to decide that tables are the better route here, but there is absolutley value in Dave (or anyone else) investigating CSS-only options.
Good work, Dave!
Simply, those who think a table would work equally well haven’t yet been in situations that require this. Once you have, you’ll be glad it exists. (Or you’ll use Mike’s fix — http://www.mezzoblue.com/archives/2004/09/16/minheight_fi/comments/#c009464 — which is nice and light, just requires the extra null div)
For everyone else, you’re welcome. Glad to share, glad it’s useful. Wish min-height were an option, but oh well.
Dave,
Instead of specifically styling a certain element inside the box, how about just classing the first element that appears inside? This way, you can still have multiple elements of the same type, and no killing of your model.
for example…
.box {width: 200px; margin: 0; padding: 0;}
*>.box {padding-top: 200px; min-height: 1px;}
*>.box .boxfirstchild {margin-top: -200px;}
* html .box {
/* IE5Mac filter \*/
height: 200px;
/* end filter */
}
And the markup could be thus…
<div class=”box”>
< p class=”boxfirstchild” > First instance < /p >
< p > Second instance < /p >
</div>
(spaces added in the p tags because it wouldn’t show up correctly in your comments for some reason)
Nice hack! Or hacks, I should say…
This hacking is also a reason many web professionals stay away from web standards, or CSS based layouts, more accurately. If a developer does not have MAC OS running, they will not be even aware that this hack needs to be implemented. Would I develop with CSS knowing or only suspecting that it will break Safari, or some other browser for that matter, and I am unable to test it? Probably not … I’d stick with a true and tried table layout that I believe has a better chance of rendering my desired design in browser I have no opportunity to test against.
ib.
Many thanks for sharing, Dave.
It’s one excellant hack — well-timed, too — since I’m working on a site at the moment, requiring just that!
Its an interesting experiment but on the test example there is a simple solution.
Using the old “faux column” trick. The first column is the menu the other is the image. The image is always 200px height so that is the min-height. Now you should add only the clearing thing and the two-colored background-image to the wrapper…
“That’s a lot of work just to avoid using tables.”
Yeah, because Zod knows nobody’s ever had to figure out a hack to make a table stay a certain size. I know I never had to use a blank.gif or to hold a table cell open back in the bad old days.
::sheesh::
As always, there’s more than one way to skin a cat. Use the method that suits you. I for one love to see new ways of trying to solve problems. Doesn’t mean I’ll ever use it but you never know.
Nice one Dave. :) This one actually might help me with something current, I’ll have to take a look at it when I get a chance. :)
I don’t understand the “Yay Tables!” talk. The only reason tables can expand like that is because they were made that way, and min-height is supposed to provide the same functionality, but people didn’t make it that way, yet. Go play with tables in Netscape 2 (when did it become a standard feature?) and you won’t be having fun designing layouts in them.
I remember what it was like when everyone realized they could do all kinds of crazy things with tables and laying out pages. They weren’t designed for that… and with all the crap with single-pixel spacer gifs, etc… you’re doing a hack. helloooooo? anybody there??? It’s a hack, lots of things are hacks. Go have a cup of tea and relax, it’s not that big a deal.
That is a way to do it, Dave came up with a different way using CSS/XHTML. And that’s good. Thanks Dave, just ignore them. ;)
Thank you very much for this nice hack!
I can see this method being quite a boon in other situations, but I don’t really think it’s necessary here.
Couldn’t you just define the height of the header element in ems, as the navigation would scale by the text-size anyway.
I can’t wait to use this method in other designs though.
Hmm to add to my post:
You would indeed need to set the picture as background then, as otherwise you’d have the same problem as before when zooming out.
Thanks for sharing Dave. I will find this very useful, cheers!
I have 1px line below the navigation box that shouldn’t be there in final example.
Firefox 0.9.3
AkaXakA - using ems doesn’t help with one of the other main concerns that Dave voiced - adding elements to the navigation list. If the navigation list were more dynamic or you wanted to add new items you would have to modify the css. With the given approach it should be easy enough just to add new items to the list and let the CSS take care of the appearance.
Dave,
Great Work! I have been struggling with this just like the rest. However, I tried to apply this to insert tabular data but it seems to break in Netscape 6.2. Yes! we still use 6.2 here. Most of my design uses CSS with the exception of an application table that generates dynamic info and sometimes there are 2 lines of data and sometimes 20. So I have been trying to get a fixed min height to prevent overlaps. Overall, excellent trick!!
A neat trick, but there’s another great way to do it too. It’s the prop method. You put a 1px wide “prop” stick along the side of your div that “holds” the div open the size of the prop. If the text extends past the prop, no problem. It works just like min-height:. (The clear div is to make sure it gets pushed down.)
I did NOT come up with this, but I forget where I saw it.
This is the HTML:
<div class=”text”>
<div class=”prop”></div>
Lorem Ipsum……
<div class=”clear”></div>
</div>
Then you have the CSS:
.prop {
height:200px;//(whatever the min-height property would be)
float:right;
width:1px;
clear:right;
}
.clear {
clear:both;
height:1px;
overflow:hidden;
}
.text{
}//Whatever style the main div would have!
It is possible to achieve a min-height using a zero px wide padding div, so taking up NO room in the parent div.
#box {height:1px; min-height:200px; border:1px solid #000; background:#eee;}
.pad {width:0; height:200px; background:#000; float:left;}
<div id=”box”>
<div class=”pad”></div>
Lorem ipsum dolor sit amet.
</div>
IE thinks the div exists and because a box height of 1px is specified it expands to contain the pad.
Thanks Dave. This would have been valuable to a recent project I worked on
A method similar to the “prop” method chet mentioned was my first approach. Sadly it made the contained floated divs tricky to control in all browsers. I settled for a little JavaScript.
I’ll know better next time!
I’ve never been a fan of these kind of “filter” hacks. Why not just use some server-side scripting to dish out something different to the browsers that need it? Seems like 6 and one half dozen here. Except that’s one of the things server scripting is designed to do. These “hacks” misuse what CSS was designed to do.
Also, I don’t think you realize what the real purpose of “!important” is. It’s really not meant to filter for browsers.
I’d much rather design a nice layout to spec and either use a script to deliver a separate style sheet to non-compliant browsers or just let it degrade gracefully.
Hum…
Your solution is indeed a good one, I needed this a few times and managed to work it out by putting a second <div> inside and at the bottom of the parent.
But your solution is nice and was at the above mentioned occasion way above my league.
I’m also asking myself “what if…”.
What if all browser become standard compliant ? But hey, it’s not going to be in the near future, and it will give me and my fellow developper some work (and short nights).
So at the occasion I might well use your elegant technique.
Thx a lot for the article anyway.
Learning is always a pleasure.
In the simplified version you need “padding-top: 0;” below “padding-top: 200px !important;” in order for it to work in IE5/5.5/6/Win.
At the moment it doesn’t work for me in Opera 7.51/Win, but it might be because of something else in my code.
Kudos to you Dave, for piecing together and sharing this solution. But still I’d have to agree with Nick that you should not so easily dismiss alternatives. For instance: if you follow chet’s suggestion on a prop element, you could just end up with another, more elegant solution:
http://www.vizi.nl/temp/asonginautumn/autumn-reinvented-long.html
http://www.vizi.nl/temp/asonginautumn/autumn-reinvented-short.html
Works in Mozilla and IE5/Mac and on Firefox0.9. Haven’t tested in IE6/Win, though, but it probably (or should I say: hopefully?) works in there as well.
I have been trying out some different approaches to this, and I think that the following is the one I like the most. Please carefully test it youself.
Try taking your example page at http://www.mezzoblue.com/tests/minheight/t4a.html and use the following two rules instead of yours:
.box {
border: solid 1px #000;
background: #eee;
width: 200px;
min-height: 1px;
height: auto;
_height: 200px;
padding-top: 200px;
_padding-top: 0;
}
.box p {
margin-top: -200px;
_margin-top: 0;
}
This works for me in IE5/5.5/6/Win, Opera 7.51/Win and Firefox 1.0 Preview/Win.
The declarations with the underscore are only read by IE5/5.5/6/Win and I like this better than using the !important method.
Also, because of the 1px border and the box-model bug in IE5/5.5/Win, the width and height will be two pixels smaller in these browsers. If you want it to be pixel-perfect, you could do it this way:
.box {
border: solid 1px #000;
background: #eee;
width: 200px;
_width /**/: 202px;
min-height: 1px;
height: auto;
_height: 200px;
_height /**/: 202px;
padding-top: 200px;
_padding-top: 0;
}
.box p {
margin-top: -200px;
_margin-top: 0;
}
IE6 DOES read the declarations with the underscore, but DOES NOT read those with the empty comment tags. This could also be used as an alternative to the Tantek Hack without the need to Be Nice to Opera (well, at least this is true in the browsers I have access to).
Could anyone please test the above method in Mac browsers? I would really like to know if it works.
Oh, talking about being pixel-perfect: I just found out that the “min-height: 1px;” makes the box 1px taller (201px) in Opera 7.51/Win and Firefox 1.0 Preview/Win than in IE/Win.
The “padding-top” and “margin-top” should be 1px less than the values feeded to IE if these things matter.
> The declarations with the underscore
> are only read by IE5/5.5/6/Win and I
> like this better than using the
> !important method.
Using ‘_’ your css code becomes invalid.
Using ‘!important’ your css is still valid
Has anyone succeeded in applying this workaround to the ever-problematic absolute footer issue? You know, the footer that shows up at the bottom of the browser window unless the content needs it to be farther down.
The lack of min-height in Safari and IE is the primary cause of lack of absolute footer support (so much that JavaScript, e.g. http://alistapart.com/articles/footers/ , seems required to be able to address the issue).
But using this technique with percentages in margin and padding values (like padding-top:-100%) truly scares away even the most compliant of browsers.
Ever the conundrum.
As Janus said, is it also possible to solve this min-height problem with the faux-column trick? By floating everything? This is no critique on your method, I think it’s very nice, but I was wondering if the all-float-thing (maybe with one clearing element) would work?
Matthijs
Ehm, I think to get it working this way.. how are you going to define the end of the view-port, huh? If you know the height of the footer then there is a solution… if not there is none! Except for using JS. Thats sad but truth.