Conrad.Dean
Conrad.Dean

Reputation: 4421

Why don’t my box borders surround the floats inside them without this CSS fix? (And how does the fix work?)

I'm teaching myself CSS and HTML, and I've come across something that seems like a bug-- it's challenging how I understand HTML and CSS. I've found a fix for this bug already, but I was hoping someone could cue me as to why the fix works, and if there's some advice out there for how to get a easier handle on CSS's inconsistencies. Below I've detailed the problem and its solution.

Problem: I have a few items that I want to be nested in a couple of boxes on the page. I've changed the CSS to draw attention the specific problem areas: The red and green boxes should be sandwiched between the black and yellow lines.

The red and green boxes are set to float to the right and left of the page. Their container does not expand to surround them, and the black and yellow lines touch eachother. After applying the magical CSS before my custom CSS, the two lines surround the red/green boxes as expected

Here are my files: template.html

<html>
<head>
    <!-- uncomment the line below to enable the fix -->
    <!--<link rel="stylesheet" href="css/resettemp.css" type="text/css" > -->
    <link rel="stylesheet" href="css/template.css" type="text/css" > 
</head>
<body>
    <section class="content">
        <header id="contact">
            <div id="name">Name</div>

            <div id="address">
                <div>Home Address</div>
            </div>

            <div id="contact-details">
                <div><strong>Phone Number:</strong>5555 </div>
            </div>
        </header>
        This text should be under everything else.
    </section>
</body>
</html>

template.css:

header#contact
{
    display: block;
    font-size: 1em;
    border-bottom: 5px #ff0 dashed;
}

header#contact
#name
{
    display:block;
    text-align: right;
    font-size: 2em;
    border-bottom: 3px #000 solid;
}

header#contact
#address
{
    float:left;
    background: #f00;
}

header#contact
#contact-details
{
    float:right;
    background: #0f0;
}

And the fix below is placed in "resettemp.css":

/* our Global CSS file */article:after { clear:both; content:"."; display:block; height:0; visibility:hidden; }aside:after { clear:both; content:"."; display:block; height:0; visibility:hidden; }div:after { clear:both; content:"."; display:block; height:0; visibility:hidden; }footer:after { clear:both; content:"."; display:block; height:0; visibility:hidden; }form:after { clear:both; content:"."; display:block; height:0; visibility:hidden; }header:after { clear:both; content:"."; display:block; height:0; visibility:hidden; }nav:after { clear:both; content:"."; display:block; height:0; visibility:hidden; }section:after { clear:both; content:"."; display:block; height:0; visibility:hidden; }ul:after { clear:both; content:"."; display:block; height:0; visibility:hidden; }/* our ie CSS file */article { zoom:1; }aside { zoom:1; }div { zoom:1; }footer { zoom:1; }form { zoom:1; }header { zoom:1; }nav { zoom:1; }section { zoom:1; }ul { zoom:1; }

sources: http://www.sycha.com/css-clearfix-floated-element-automatically-fill-parent-container

and then the CSS above: http://www.marcwatts.com.au/blog/best-clearfix-ever/

How do I understand how this CSS fix works?
How do I teach myself the basic syntax of CSS in addition to understanding these peculiarities? It seems I'm probably using floats to accomplish formatting goals improperly-- What's the more acceptable way to get two boxes of text on opposite sides of a container underneath another block element like this?

Browser: google chrome 10.0.648.205

Upvotes: 6

Views: 4323

Answers (3)

Richard JP Le Guen
Richard JP Le Guen

Reputation: 28753

The "Problem"

Here is a diagram, fom the w3c, showing what happens when a float overlaps borders of elements in the normal flow.

A floating image obscures borders of block boxes it overlaps.

This behavior of floating elements causes its parent element's height to do things most developers consider unintuitive.

But given that it is documented on the w3c, this is intentional: it is not a bug.

The Solution You Found

So here's the interesting rule in your CSS:

/* our Global CSS file */
header:after {
    clear:both;
    content:".";
    display:block;
    height:0;
    visibility:hidden;
}

This rule is targeting the <header> element, but it's also using the :after pseudo-element. The result is that it's like there was an imaginary element after <header> which you are targeting with this CSS rule:

<!DOCTYPE html>
<html>
<head>
    <!-- uncomment the line below to enable the fix -->
    <!--<link rel="stylesheet" href="css/resettemp.css" type="text/css" > -->
    <link rel="stylesheet" href="css/template.css" type="text/css" >
    <title>Teaching myself CSS, HTML. I want help understanding this bug.</title>
</head>
<body>
    <section class="content">
        <header id="contact">
            <div id="name">Name</div>

            <div id="address">
                <div>Home Address</div>
            </div>

            <div id="contact-details">
                <div><strong>Phone Number:</strong>5555 </div>
            </div>
        </header><!-- imaginary header:after element -->
        This text should be under everything else.
    </section>
</body>
</html>

This imaginary header:after "element" which is added after the <header> has a clear:both CSS property:

/* our Global CSS file */
header:after {
    clear:both; /* This property clears floating elements! */
    content:".";
    display:block;
    height:0;
    visibility:hidden;
}

So what does clear do? According to the w3c...

This property indicates which sides of an element's box(es) may not be adjacent to an earlier floating box.

The less reliable but sometimes clearer w3schools describes clear as...

The clear property specifies which sides of an element where other floating elements are not allowed.

Since the header:after "element" has a clear:both CSS property, is will appear at the bottom of (after) any floating elements on either its left or right sides, such as your red and green boxes.


Now, that resettemp.css file seems to target almost every element imaginable with the same trick - kind of a carpet-bomb approach to solving the float-overflow problem. A better idea is to learn CSS :P


You could also use header { overflow:hidden; } - depending on your needs.

Upvotes: 7

Paul D. Waite
Paul D. Waite

Reputation: 98796

To explain your “bug”:

The red and green boxes are set to float to the right and left of the page. Their container does not expand to surround them, and the black and yellow lines touch each other.

That’s not a bug, that’s how floats work. Floated elements do not take up vertical space in their ancestor elements. This is because floating was originally designed to enable text to flow around images — if you have a floated image inside a paragraph of text, and it’s taller than the text in that paragraph, you generally want the next paragraph to also flow around the image.

To explain how your “fix” works, for your HTML it’s this bit that does it:

header:after {
    clear: both;
    content: ".";
    display: block;
    height: 0;
    visibility: hidden;
}

It works thus:

  1. The :after pseudo-class effectively adds an anonymous HTML element after the element specified by the rest of the selector (which we’ll call the original element), and allows you to style it. Which is a bit meaningless without...

  2. ...the content property. This gives the anonymous element some content, allowing it to affect the layout of the page.

  3. display: block and clear: both make this anonymous element clear any floats that come before it (i.e. the floats within the original element). The anonymous element appears after the content box of the original element, but before the padding, border and margin boxes, which is why the clearing pushes the original element’s border down past the floats.

  4. height: 0; and visibility: hidden; then make the anonymous element invisible, but don’t prevent it from affecting the page’s layout.

Your “fix” repeats this CSS for div:after, article:after and aside:after. I’m not sure why it doesn’t just use all three selectors together on one CSS rule, i.e.

header:after,
article:after,
aside:after,
div:after {
    /* Fix CSS here */
}

Or indeed apply the CSS to a class instead of elements, so that you can choose when to apply it, e.g.

clear-floats:after {
    /* Fix CSS here */
}

Upvotes: 2

EdmundYeung99
EdmundYeung99

Reputation: 2511

A good tool to debug html/css is FireBug with Firefox. You can dynamically edit the html and css to get real time results.

When you float an element, it no longer expands the parent element, hence the header height shrinks to the height of your #name block, which is not floated. Same with the bottom text, it gets pushed up because the floated elements "float" on top.

Do a clear both (which clears the floats)

<body>
    <section class="content">
        <header id="contact">
            <div id="name">Name</div>

            <div id="address">
                <div>Home Address</div>
            </div>

            <div id="contact-details">
                <div><strong>Phone Number:</strong>5555 </div>
            </div>
            <div style="clear:both;"></div>
        </header>
        This text should be under everything else.

    </section>
</body>

Upvotes: 2

Related Questions