demosthenes.info

A blog by Dudley Storey on , , , , , , and anything else that strikes his fancy.

featured articles

popular favourites

CSS and divs: The Float Flag Quirk

Like the “float quirk” discussed earlier, the “float flag” problem is by no means limited to inside divs. It is, however, encountered most often with those elements, so that will be the example I use here.

Take most any element – in our example, we’ll use a div. Place a border on it. Put another element – ideally, something with a significant height, such as an image - inside the first, and float the inner element.

You would expect the border of the outer element to fully enclose the inner floated element. You’d be wrong.Float flag problem screenshot

Why does this happen? (And, by the way, this does not happen in IE6, which breaks the rules in this regard yet again, even though it would seem to be the right thing to do).

Put very simply, floated elements do not contribute to the implied height of elements that contain them. The moment you float something, the height added by that element to its container disappears.

Under most circumstances, this is actually not a problem: there is usually plenty of non-floated content to “buffer” the container out and enclose everything. But when text content is paltry, or if the floated content is relatively large in size, and you have a border or background to the container that would draw attention, this “float flag” problem appears.

The immediate response of most designers is to set a height on the containing element that allows enough room for the floated element. But that immediately breaks the rule that we discussed earlier, and leads to a entire set of new problems as soon as the content changes in any way.

Essentially what we need is a way of making sure that there is something beneath the floated element, something that is not floated itself. That way the containing element will make itself tall enough to contain that bottom element, and thus also contain the float.

There is one simple solution, that should work for all browsers: set the overflow property for the containing div to a value of hidden. Assuming that this div has a class of clear fix:

  1. div.clearfix { overflow: hidden; }

If this doesn't work for your targeted browser, we need to get something under the floated element.

We actually have some CSS that accomplishes that, discussed in an earlier entry: clear. If our floated element is to the right, and if we make any kind of content inside the container that has a style of clear: right, that content has to be beneath the floated content, just as our earlier float quirk solution for images demonstrated.

Once designers see this solution, most are happy to shove any content in the container, clear it and move on. But this is inelegant: not only would we have to repeat this procedure every time we encountered this problem, but adding content or markup to solve a presentation problem is a Bad Thing. (This also directly addresses those of you who would force <br />’s, empty paragraphs, &nbsp’s and all sort of other abominations into code in order to get “extra space”. None of it is necessary, easily adjustable, semantic or elegant.)

What we want is a way of automatically generating something just before our <div> closes, something that doesn’t involve extra markup. We have just such a tool, in the pseudo-selector :after.

Under the assumption that there is the potential for multiple divs on any page to have this issue, we will make this a class:

  1. div.clearfix:after { content: “ ”; display: block; clear: both; }

An example of the markup to which this CSS might be applied:

  1. <div class="clearfix">
  2. <img src="tree-in-winter.jpg" alt="Tree In Winter" title="Tree In Winter"
  3. style="width: 375px; height: 500px; float: right; padding: 1em; 1px solid grey;" />
  4. <blockquote>
  5. <h4>Self-Pity</h4>
  6. <p>I never saw a wild thing<br />
  7. sorry for itself.<br />
  8. A small bird will drop frozen dead from a bough<br />
  9. without ever having felt sorry for itself.</p>
  10. <cite>D. H. Lawrence, 1929</cite>
  11. </blockquote>
  12. </div>

(Two things to note: first, we can place an image immediately inside a div, as div is a block element. Second, this example contains one of the few valid uses of the <br /> tag, which forces a line break: “Self-Pity” is a poem, with text that would normally be in a single paragraph broken into different lines.)

Again, this should work for most all browsers. If you still have issues, substitute a period for the space we generated above. If you do so, you might be hard-pressed to find the generated period, but it is there. It even adds a tiny amount of space below the image.

So what did we do? You can see from this example that the :after pseudo-selector really isn’t really “after”: more accurately, it should be called “last thing added inside the element”.

We’ve made the space (or period) we generated block, so it appears on its own line. We’ve cleared it, on both sides, so it doesn’t matter on which side the last floated element appears: clear: both will handle both left and right.

We could leave things here, but if you found that you needed to use a period, we really should hide all traces of our sneaky fix. We can’t change the display of our period – that’s already set – but we can alter its visibility:

  1. div.clearfix:after { content: “.”; display: block; clear: both;
  2. visibility: hidden; }

Now the period is no longer visible. But as we discovered in the simple CSS gallery example, making something hidden still leaves the blank space where it was. We can’t use the trick we used then – using position: absolute – because we want to keep the period exactly where it is. How then can we remove every sign of it, yet still leave it in place to solve our problem?

  1. div.clearfix:after { content: “.”; display: block; clear: both;
  2. visibility: hidden; line-height: 0; }

Float flag fixed screenshotThat truly hides the period. Now there is no contribution to the height of the div from our period, yet it still remains in place.

We’ve created this trick as a class, so it can be applied to as many divs as you wish. If you wanted to use this technique universally, you could rename the selector to simply .clearfix, without the preceding div which would enable you to apply it to any element, not just divs.

The class, as written, could be applied to any div, including divs that already have an id and / or an inline style. But what if the div you wanted to use it on already had a class applied? In that case, you could use a little-known but very helpful technique that allows you to apply two classes at once.

Let’s say that your div had a class called .candyland applied to it.

  1. <div class=”candyland”><p>Candyland is a happy place…</p></div>

Let’s also assume that you have a floated element inside the div, one that causes the problem we have been discussing. You want to keep the .candyland class but also apply .clearfix. Modifying the class attribute value of the div to include both will provide the solution:

  1. <div class=”candyland clearfix”><p>Candyland is a happy place…</p></div>

Technically, you can use this trick to simultaneously apply as many classes as you wished to an element. So long as they have a space between them, each word in the class attribute value will be assumed by the browser to be a separate reference, and their associated styles will be conjoined in the appearance of the element.

web developer guide

featured comment

by JoelB in Goodbye, JQuery Validation: HTML5 Form Errors With CSS3

what i'm reading

A Storm of Swords: A Song of Ice and Fire: Book Three
A Storm of Swords: A Song of Ice and Fire: Book Three

what i'm watching

Californication: The Third Season
Californication: The Third Season

what i'm playing

Mass Effect 3 Collector's Edition
Mass Effect 3 Collector's Edition

what i'm hearing

Dub FX
Dub FX

blogs

podcasts

no ads ever

This blog is free of advertising, and always will be.

creative commons licensed

The content of this blog is free to use in whatever way you wish under the Creative Commons license.