Forum Moderators: not2easy
It's not just the end result that I aim for, I aim probably more at showing the thought process of how to build your design without tearing out the last few hairs you've left :)
No IE
Yes, that's the start: ditch the browser of choice of the majority of your users. It's critical to do this is you value your sanity.
Chose any other browser: FF, Safari, Opera, ... I'll use Firefox for it has plug-ins like the web developer toolbar and firebug. But the others will work too as long as it's not "that" browser from Microsoft.
Start
I'm using a template for the html to start from.
Make it as strict as you can cause it will increase the number of errors you get from a code validation and make your code a lot better as a result.
I usually start from this in these guides:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
The main thing I'd do different in a real life case is that I'd make the CSS a <link>. But for simpler cutting and pasting in this tutorial this will do.
HTML
Yes: make the html first.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<div class="header">
<a href="#"><img src="1.jpg" alt="logo" /></a>
<h1>title</h1>
</div>
<div class="middle">
<h2>heading</h2>
<p>Lorem ipsum ...</p>
<p>Add more content to make sure you can scroll as you need.</p>
</div>
<div class="footer">
<p>Footer text goes here</p>
</div>
</body>
</html>
Now does that validate ?
Yep it does!
Does it make sense without CSS ?
It does!
HTML done
I'll consider the HTML finished now. All the rest will have to be done in the CSS.
The 100% height framework
First let's center our body and give it a different color from the background
html {
background-color: #ccc;
}
body {
background-color: white;
width: 770px;
margin: 0 auto;
}
Why does this center it ?
Well the block element <body> is given a width and told to calculate it's left and right margin itself.
Next let's stretch it vertically to be at least the height of the viewport
html {
height: 100%;
}
body {
min-height: 100%;
}
The 100% height trick is all about: the 100% references the height of the direct parent, provided the parent has an explicitly set height different from "auto".
The exception is the root element that has the height of the viewport.
min-height instead of height is what makes it at least as high as the content (and not cut our body off where the viewport stopped).
Try it with different sizes of viewport and different sized content a bit.
Now what would happen if we were to add a border or padding or vertical margins to <body> ? Try it !
So remember we need to avoid adding anything that's going to add to the height of the body. The 100% sets the height of the content, not the overall height.
So we'll need to add the border in a different fashion then.
Stick the footer to the bottom
By stick to the bottom in this case I meant stick it under the content if the content is longer than the viewport, and stick it at the bottom if the content isn't long enough to fill the viewport.
You can also stick it always at the bottom of the viewport: you use position fixed instead of position: absolute in that case.
Absolute positioning:
body {
position: relative;
}
.footer {
position: absolute;
background-color: yellow;
bottom: 0;
left:0;
}
Nice, but the footer is lacking the width it needs.
I'm sure after the talk about 100% height most would wonder about 100% width:
.footer {
width: 100%;
}
There are ways to deal with that (and we'll show them where we deal with IE6 much later).
The reason the width get's too large is cause we derive the overall width from the width of the content (which we can set), and then the padding is added around that.
But when we use absolute positioning, setting the overall with is more than easy enough:
.footer {
position: absolute;
background-color: yellow;
bottom: 0;
left:0;
right:0;
}
Yes, we set left and right and the width will adapt to what's needed.
We can now set the padding as we like. Try it!
Layout the header
I need to fix the header (mostly cause my test image is way too large), but also to show some neat tricks.
Let's remove that ugly blue border:
a img {
border:none;
}
This will remove borders on all images that are inside a link.
Let's also position and size the header:
.header {
background-color: orange;
position: relative;
min-height: 110px;
}
.header a img {
width: 150px;
height: 100px;
position: absolute;
top: 5px;
left: 5px;
}
.header h1 {
padding: 20px 0 0 160px;
}
You can lay it out as you like, it's just one way, nothing more.
Fix the overlap
If your content is larger than the viewport, the footer is sitting on top of the content itself. This needs fixing.
But the footer is absolutely positioned so it has no influence over the in-flow elements.
The solution is to make sure the content has whitespace that sticks out below the footer:
.middle {
padding-bottom: 2em;
}
Now why does this work?
The middle div isn't stretched ?
Nope but it's got a padding sticking out beyond it's content that leaves room for the footer to overlap should it want to do that.
To visually see it at work: add a background color on .middle and resize your browser window.
Adding some padding
Where to add padding is tricky:
So what works ?
.middle {
padding: 0 5px 2em 5px;
}
.footer p {
padding: 5px;
font-size: 80%;
}
I've collapsed the 2em bottom padding into the shorthand padding on the .middle
The .footer p can have padding, its width isn't set.
I already took care of the header above.
Adding a border
A border is just as tricky as the padding above, but we can add left and right borders on the body and we can add a top border on the header and a bottom border on the footer:
body {
border-left: 1px solid #888;
border-right: 2px solid black;
}
.footer {
border-bottom: 2px solid black;
}
.header {
border-top: 1px solid #888;
}
Removing the background colors showing us where the elements are and putting it all together we end up with:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
html {
background-color: #ccc;
height: 100%;
}
body {
background-color: white;
width: 770px;
margin: 0 auto;
min-height: 100%;
position: relative;
border-left: 1px solid #888;
border-right: 2px solid black;
}
.footer {
position: absolute;
bottom: 0;
left:0;
right:0;
border-bottom: 2px solid black;
}
a img {
border:none;
}
.header {
position: relative;
min-height: 110px;
border-top: 1px solid #888;
}
.header a img {
width: 150px;
height: 100px;
position: absolute;
top: 5px;
left: 5px;
}
.header h1 {
padding: 20px 0 0 160px;
}
.middle {
padding: 0 5px 2em 5px;
}
.footer p {
padding: 5px;
font-size: 80%;
}
</style>
</head>
<body>
<div class="header">
<a href="#"><img src="1.jpg" alt="logo" /></a>
<h1>title</h1>
</div>
<div class="middle">
<h2>heading</h2>
<p>Lorem ipsum ...</p>
<p>Add more content to make sure you can scroll as you need.</p>
</div>
<div class="footer">
<p>Footer text goes here</p>
</div>
</body>
</html>
Test
Let's test it first in the other standards compliant browsers:
Seems to work fine in FF, Opera, Safari and Chrome.
So this is another milestone like the one where we declared the html done. The CSS is now done.
I can hear you think: but you didn't even test it in IE ! How can it be done ?
Yes it's done. We'll add conditional comments to work around issues that IE has.
The reason for not adding anything back into the main CSS is to keep it all simple and possible to wrap our head around. And mainly not to have to care why IE does what it does.
Work around IE bugs
To work around the bugs in IE we need to test it first. Easiest is IE8 in most cases, most difficult is IE6 in virtually all cases.
IE8: does OK as expected
IE7: does OK as well (I had hoped to have something to fix to be honest)
IE6: there's no chance it'll do it properly
IE6 doesn't understand min-height, but its height is broken enough to be able to be a good substitute.
And the setting of both sides on the footer isn't working either (expected)
Adding the conditional comment to fix it:
<!--[if IE 6]>
<style type="text/css">
body {
height: 100%;
}
.header {
height: 110px;
}
.footer {
width: 100%;
}
</style>
<![endif]-->
This yields:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
html {
background-color: #ccc;
height: 100%;
}
body {
background-color: white;
width: 770px;
margin: 0 auto;
min-height: 100%;
position: relative;
border-left: 1px solid #888;
border-right: 2px solid black;
}
.footer {
position: absolute;
bottom: 0;
left:0;
right:0;
border-bottom: 2px solid black;
}
a img {
border:none;
}
.header {
position: relative;
min-height: 110px;
border-top: 1px solid #666;
}
.header a img {
width: 150px;
height: 100px;
position: absolute;
top: 5px;
left: 5px;
}
.header h1 {
padding: 20px 0 0 160px;
}
.middle {
padding: 0 5px 2em 5px;
}
.footer p {
padding: 5px;
font-size: 80%;
}
</style>
<!--[if IE 6]>
<style type="text/css">
body {
height: 100%;
}
.header {
height: 110px;
}
.footer {
width: 100%;
}
</style>
<![endif]-->
</head>
<body>
<div class="header">
<a href="#"><img src="1.jpg" alt="logo" /></a>
<h1>title</h1>
</div>
<div class="middle">
<h2>heading</h2>
<p>Lorem ipsum ...</p>
<p>Add more content to make sure you can scroll as you need.</p>
</div>
<div class="footer">
<p>Footer text goes here</p>
</div>
</body>
</html>
[edit]Edit: spelling, grammar and layout[/edit]
[edited by: swa66 at 12:13 pm (utc) on Nov. 11, 2009]
First, wrap the entire body contents in an extra div like so:
<div id="wrapper">
<div class="header">
<a href="#"><img src="1.jpg" alt="logo" /></a>
<h1>title</h1>
</div>
<div class="middle">
<h2>heading</h2>
<p>Lorem ipsum ...</p>
<p>Add more content to make sure you can scroll as you need.</p>
</div>
<div class="footer">
<p>Footer text goes here</p>
</div>
</div>
Then, add the following code just above </head>:
<!--[if IE 8]>
<style type="text/css">
#wrapper {height:100%;display:table;}
</style>
<![endif]-->
Let me know if that works!
Anybody else that can trigger this with IE8 and the code provided ?
The thing is I've not seen it in IE7.
But the fix to give IE8 a relative height somewhere that's got no direct parent with an explicitly set height (and hence computes to auto) is simple and remind me of the old hasLayout triggers (it's not a hasLayout related bug AFAIK)
So that gives:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
html {
background-color: #ccc;
height: 100%;
}
body {
background-color: white;
width: 770px;
margin: 0 auto;
min-height: 100%;
position: relative;
border-left: 1px solid #888;
border-right: 2px solid black;
}
.footer {
position: absolute;
bottom: 0;
left:0;
right:0;
border-bottom: 2px solid black;
}
a img {
border:none;
}
.header {
position: relative;
min-height: 110px;
border-top: 1px solid #666;
}
.header a img {
width: 150px;
height: 100px;
position: absolute;
top: 5px;
left: 5px;
}
.header h1 {
padding: 20px 0 0 160px;
}
.middle {
padding: 0 5px 2em 5px;
}
.footer p {
padding: 5px;
font-size: 80%;
}
</style>
<!--[if IE 6]>
<style type="text/css">
body {
height: 100%;
/* min-height not working */
}
.header {
height: 110px;
/* min-height not working */
}
.footer {
width: 100%;
/* setting left and right at the same time not working */
}
</style>
<![endif]-->
<!--[if IE 8]>
<style type="text/css">
.middle {
height: 1%;
/* min-height not updating on vertical enlarging of the window */
/* parent has no explicit set height so the computed value will */
/* be auto */
}
</style>
<![endif]-->
</head>
<body>
<div class="header">
<a href="#"><img src="1.jpg" alt="logo" /></a>
<h1>title</h1>
</div>
<div class="middle">
<h2>heading</h2>
<p>Lorem ipsum ...</p>
<p>Add more content to make sure you can scroll as you need.</p>
</div>
<div class="footer">
<p>Footer text goes here</p>
</div>
</body>
</html>
There is another bug I discovered while looking revisiting this: opera has a weird one: it doesn't do the min-height: 100% on first load, but does so when you reload. (I had missed it due to reloading the page instead of loading it)
I've found complex solutions out there with a float that's generated from the :before, but I'd love a simpler one.
The thing is I've not seen it in IE7.
(it's not a hasLayout related bug AFAIK)
Yes, I can confirm that it seems to be a hasLayout bug (with hasLayout being false == bad thing in IE8 in this case). I tested some more, and in both IE7 & IE8 it alerts false for hasLayout without the height fix applied (and footer works in IE7 but not in IE8), and true with the height fix applied for .middle (footer works in both). You can play with checking this with the following script, add before closing head tag in your latest post (swa66), and then play with removing and re-adding the IE8 conditional css:
<script type="text/javascript">
window.onload = function () {
var div = document.getElementsByTagName('div')[1];
alert('div.className = '+ div.className +'\ndiv.currentStyle.hasLayout = '+ div.currentStyle.hasLayout);
};
</script>
So it's something that's fixed by giving hasLayout to a child of the element that's not stretching in IE8 ...
The header and footer already had hasLayout. So the middle not having it was apparently enough to trigger this bug.
Wonder what else we'll find of hidden flashbacks from the past in IE8.
According to my Analytics for the last month, 33.72% of all visits were made using any version of Internet Explorer. Of the Internet Explorer visits,
48% were using IE8
34% were using IE7
17% were using IE6
So only 6% of all visits were made using IE6. I don't doubt that the figure varies from site to site, but surely they're a dying breed? Why not give them a push in the right direction?
Of course, I'm not selling anything, so I can afford to treat IE6 users like lepers.
The advantage of doing IE last is that you can do those that you care about. Ad you can put as much effort it in as you want (in this case: we know IE6 doesn't do min-height, and we know an easy fix, so why not?)
Those using IE6 are already finding much of the internet both broken-looking and broken functionally so if your site is broken but functional, you are serving IE6 users well.
So I just stick to W3C standards, test in Firefox, Opera, Lynx, etc, and don't bother testing in IE at all. If MS can get their browsers to render standards-based markup properly, great.
As I said, it really helps that I'm not selling anything.