Forum Moderators: not2easy
:
:
Hi,
Can someone please help me before I go crazy? This works in IE, but not in FireFox - why does the border of the #mycontainer DIV not enclose the DIVs nested within it?
[blogs.org...]
CSS
body { text-align: center; }
#mycontainer {
width: 300px;
border: 1px;
border-style: solid;
border-color: #000;
font-family: Verdana, Arial, Helvetica, sans-serif;
}
#mytitle {
width: 288px;
padding: 6px;
background-color: #666;
color: #fff;
}
#mycontent {
width: 288px;
padding: 6px;
color: #000;
}
#myleftcolum {
float: left;
clear: both;
width: 144px;
background-color: #fcf;
}
#myrightcolum {
float: left;
width: 144px;
background-color: #cff;
}
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
<link href="stylesheet.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="mycontainer">
<div id="mytitle">
Title
</div>
<div id="mycontent">
<div id="myleftcolum">Left</div>
<div id="myrightcolum">Right</div>
</div>
</div>
</body>
</html>
First off, why is this a problem in Firefox (and other standards compatible browsers)?
You‘ll find that your #mycontent <div> is actually enclosing #mytitle, just not #mycontent and its children. Why’s this? Well, floated elements like #myleftcolumn and #myrightcolumn will (according to the specs) not force their parent to contain them. The reasoning behind this is better demonstrated if you think about a simpler solution: a <p> with a floated <img> inside it. Imagine that that <img> was 1000px tall. What you’d want to happen is any text in that <p> parent to wrap around the <img>, then any text in following <p>s to wrap around it as well. What you wouldn’t want to happen is for the parent <p> to expand to fit the <img> leaving a big block of empty white space.
Here, the parent container is #mycontent. As both of its children are floated it collapses as it now contains no content that’ll prop it open. The same applies to #mycontainer; it collapses to fit it’s non-floated content which here is only #mytitle.
So, solutions. There’s various ways around this effect. Floated elements always contain their floated children so you could float #mycontainer. Elements with an overflow that’s not visible (so hidden & auto) will also contain their floated children. However you don’t always want to float elements and I’ve found that overflow settings can cause problems in older versions of Netscape (7.1 and below).
The simplest solution is to insert a ‘prop’ element. We know that we can give an element a ‘clear’ property that’ll make it clear any previous siblings that are floated. Knowing this, we can insert a small element that will prop open the parent container by clearing the floated siblings. To use your example:
<div id="mycontent">
<div id="myleftcolum">Left</div>
<div id="myrightcolum">Right</div>
<div style="clear: both;"></div>
</div> This is very cross-browser compatible, but obviously required the insertion of an extra element which goes away from the point of a CSS layout in the first place: the separation of content and style. Luckily there’s a feature in CSS2.1 that can replicate this exact fix without adding extra markup: generated content. Generated content lets you add small pieces of content to a document and style it all through the stylesheet. We can use this to our advantage by inserting our prop element directly from the stylesheet. This method was first discovered and detailed on positioniseverything.net [positioniseverything.net], and in your case would look something like:
#mycontent:after {
content: ".";
clear: both;
display: block;
visibility: hidden;
height: 0;
} A quick rundown: the ‘:after’ is a pseudoelement that is inserted at the end of #mycontent. Into it we’re adding a full-stop, making that element clear the previous floated siblings, then hiding it. This technique works in all modern browsers with the notable exception of IE. Luckily we’re not seeing the problem in IE, but that just begs the question...
Why isn’t this a problem in IE?
IE is a strange beast at times. One of the most notable oddities is a internal concept it has called hasLayout. While this isn’t something you should have to know about as a CSS developer you’ll find that a lot of the bugs and inconsistencies you come up against on a day to day basis can be much more easily dealt with if you have some understanding of hasLayout. I’d recommend reading Ingo Chao’s excellent essay on the subject [satzansatz.de] if you have time.
In this particular situation hasLayout is coming into play on #mycontent because you’ve set a width on it - width is a trigger property for hasLayout. So now you’ve triggered it what are the consequences? Well, one of hasLayout’s effects is to force the affected element to contain its floated children - exactly the effect we want here. As per usual with IE it’s a fight-bugs-with-bugs solution :)
Setting a width isn’t always the ideal solution but here it works. In future if you come up against a similar situation where setting a width isn’t possible then I’d recommend setting zoom:1 which is another hasLayout trigger. It won’t validate but as it’ll only ever be used for hasLayout triggering it’s self-documenting, and unlikely to ever become a problem in the future.
Edit: ah, you discovered the overflow solution already. Well, hopefully this will throw some light on the original problem :)
[edited by: Robin_reala at 11:25 pm (utc) on Feb. 11, 2007]