TV version (Display Regular Site)

Skip to: Navigation | Content | Sidebar | Footer


Weblog Entry

Simple, It Ain’t

June 24, 2003

Anyone who says CSS is easy hasn’t had enough experience with it. It is easy if things go right; it is a bottle of Tylenol if things do not.

Example 1 — precisely the sort of thing I’m talking about. Take this simple block of code:

<div id="main">
	<span>
	<p>multiple paragraphs here</p>
	</span>
</div>

Try to give the span a border, if all the paragraphs are floated. It can’t be done, even if the span is a block–level element.

This should be possible, block level or not. Unless the text is removed from the document stream via absolute positioning, it should be contained within the span, which means it gets a border. However, and this is a problem amongst every browser, the floated text is treated as independent of the document stream. Hence: no border.

This is inconsistent behaviour. Floated items are not supposed to be removed from the document flow — you’ll notice how nicely the non–italicized paragraphs in example 2 wrap around the italicized text. This is expected. So why no border in example 1?

CSS is powerful, but with great power comes grea… strike that. Let’s just say it’s not easy and leave it at that.

update: Simon pointed out that my example is actually invalid, since block–level elements shouldn’t be contained within inline elements. The span is invalid when surrounding the paragraphs. But! Even when corrected, the problem holds — see example 3 for a div in place of the span.


Reader Comments

Arikawa says:
June 24, 01h

The :after doesn’t “feel” like a hack to me. Well at least it doesn’t involve something like “"}"” : )

Anyway, quite informative. I’m glad to know that I can expand a container to a floated contained element’s height.

June 24, 04h

I edited your example3 and created this:

example4

The changes are as follows:

* Added height: 100%; to #main div
- This fixes IE.

* Added a <div> after the last paragraph with a clear: both;
- This fixes Moz/Opera.

Tested in IE6, Moz 1.4, and Opera 7.

June 24, 05h

Excellent! I updated my page to include the “height: 100%” trick.

June 24, 06h

Groovy. :)

As an addendum to my previous post I thought Iíd mention that I discovered the clear: both; trick for enclosing floats through this ALA article.

June 24, 08h

I may be wrong, but it’s possible this is due to span being an inline element. Inline elements aren’t allowed to contain block level elements, and p is a block level element. Promoting span to block level using “display: block” doesn’t stop this from being invalid HTML, and it could be this that it causing the problem.

Dave S. says:
June 24, 08h

Bonehead move on my part. You’re right about the span/p conflict.

But in this case it’s equally true of proper block-level elements — Example 3 with a div in place of the span.

June 24, 08h

Yes it is invalid (with a strict doctype), but the span should still surround the paragraph.

And you can put a border on it:

p {
float: left;
width: 50%;
}

span:after {
display: block;
clear: both;
content: “”;
}

span {
border: 1px solid red;
display: block;
}

…works fine in Gecko and Opera 7.

Guy says:
June 24, 08h

I think Simon has hit the nail on the head there. Spans really ought to be inside block level or other inline elements but never contain block level elements.

Dave S. says:
June 24, 08h

I shouldn’t have to work that hard though, Tom. Assuming I’m using a correct block-level element (see example 3, which I was posting at the same time as you) there’s no need to get into :after.

Or, well, there shouldn’t be.

June 24, 08h

I totally agree you shouldn’t have to - which is why I campaigned (er, that’ll be writing one email to www-style then) for a way to make foats affect their parent’s height.

Personally I think looking at practical, real-world problems with the current CSS specs is an excellent thing to do right now - take each case at a time, and see if there can be a solution found for CSS3 (even if that’s a looong way off being properly implemented).

Mike says:
June 24, 09h

>floats affect their parent’s height.

They do already no? (I’m sure the specs mention that)

Or, at least the facility exists with clear:xxx. Or is that considered a hack?

June 24, 09h

No, floated elements (and absolutely positioned elements) should not affect the height of any other element. You can use :after or a clearing span to force them to, but yes, I consider that a bit of a hack.

MikeyC says:
June 24, 10h

“Anyone who says CSS is easy hasnít had enough experience with it.”

Its not CSS, but a browser’s implementation of CSS that usually gives me headaches. Although in some instances the spec is, indeed, to blame.

June 24, 10h

“No, floated elements (and absolutely positioned elements) should not affect the height of any other element. You can use :after or a clearing span to force them to, but yes, I consider that a bit of a hack.”

Actually, that is the only way (and the way the W3C encourages you to handle it), so it shouldn’t really be considered a hack.

Quick question - I am not sure exactly what you are trying for. Do you have a mockup we could see? It seems you want all the paragraphs to be floated, but you also want them to do text wrap? Or do you want example 2 with a border around everything? Maybe I’m just dense…

Dave S. says:
June 24, 10h

I’m going to have to question the W3C on this choice. I’ve run into a lot of float problems that would have simply gone away if the containing element had expanded with the height of the content. The :after method, while it may be officially sanctioned, just plain feels like a hack. Can someone tell me who I need to talk to about this?

Mark - examples 1 & 3 should have a border around all the text. You get a border when the paragraphs are not floated, so it doesn’t make sense if they don’t get a border when they float. Example 2 was only to illustrate how a floated element is left inside the document stream, which means simply that it takes up space. Basically, the content isn’t affecting the parent element when I think it should.

(I ran into this problem developing something real-world, which isn’t available for public consumption yet.)

16
Claire says:
June 24, 11h

Thanks for that page Matt, I always used the clear: both; solution up until now but the CSS workaround (nicer word than hack, don’t you think ;)) keeps the mark up clutter free

And Eric too.. I like explanations that help me remember the whys ;)
I’m not too hot on interpreting specs..

Claire

Eric says:
June 24, 11h

Floats can’t auto-expand to contain their parents. Consider the following fairly common typographical effect, which is easily possible in HTML 3.2:

<p>
blah blah blah <img src=”bar.gif”> blah blah
</p>
<p>
yadda yadda yadda
</p>

Now assume the image has been floated. If the paragraph were forced to grow to contain it, then there would in many situations be a huge gap between the end of the text in the first paragraph, and the beginning of the second paragraph.

This is how browsers worked ever since Netscape 1.whatever, when floating was introduced as an ‘align’ value. So CSS replicates that, and it’s right to do so. The alternative is far less pleasant. CSS3 has a proposed property or two that would let you change the containment policy when it comes to floats and their parents, but now that IE/Win’s entered a period of fossilization… well, let’s just say I suspect we’ll be waiting a while.

Oh, and yes, table cells do traditionally expand to contain floats. Table styling wasn’t dealt with in CSS1, when the original float rules were written. It still can’t be explained in CSS2 (or CSS2.1) terms without resorting to explanatory text. Thus the CSS3 proposal.

Dave S. says:
June 24, 11h

Maybe that’s why this seems illogical to me - I compare block level elements to table cells even to this day, and expect some solidarity. That’s obviously a flawed assumption.

Good point about the image. In my example 2 the paragraph to the left spans multiple paragraphs, which is exactly the expected behaviour and something I took for granted. I would have been right pissed if it didn’t.

And here I thought this stuff was difficult…

June 24, 11h

Nobody noticed yet, there is a broken link in your article hidden under the name “example 3”:
http://www.mezzoblue.com/cgi-bin/mt/mezzo/archives/<a href=, I think it will be no problem to correct that?

Maybe it’s possible to give the p element a border? and you give te top- and bottom-border with first-child and list-child, if that’s possible you won’t even need the extra div.

And a little off-topic: Does anyone know why mozilla doesn’t handle this properly:
a#foo:hover + span
I would like to repport this through bugzilla, but the interface for doing that is just to uge for me :).

June 24, 12h

Damn my first post here screws your validation: link

I’m sorry.

Dave S. says:
June 24, 12h

Don’t sweat it Anne - I’ve been a bit loose with ampersands in my URLs lately, so even my front page is having trouble with the validator today.

Sigh. (thanks for the note - the link is fixed)

June 24, 12h

“Does anyone know why mozilla doesn’t handle this properly:
a#foo:hover + span”

Yes, it’s a bug.

June 24, 12h

I tackled the same problem just last week.

The most common solution I’ve seen is adding an empty block-level element with “clear: both” to the end of the inner div, forcing it to contain all of its floated children.

The current CSS3 working draft includes a new “clear-after” property, to achieve the same effect without any ugly presentational markup.

I wrote up a brief article on how to simulate the clear-after property using CSS2 generated content.