Sunday, October 26, 2008

Don't Ever Put Block Inside Inline Elements

It's been incredibly busy at work so I haven't blogged at all in over two months.

I did discover something which may seem obvious to you, but is worth repeating. Don't ever put block elements inside inline elements. If you do, in most cases, nothing bad will happen. If you do, watch out. It's better not to do it. Here's what the W3C spec says.
Probably many of us do it anyways and it seems to work, but it's "go
to hell" incorrect. Block elements visually begin on a new line.
They can contain inline and other block-level elements ( div, p, ul,
etc. ). Inline elements visually don't begin on a new line. They
contain only text and other inline elements ( span, a, img, etc. ).

Take this example of the two Colas --



Visually, they look identical, but study the HTML and you'll see that they're constructed differently.

Block in Inline Element
<a href="#">
<img src="./captainColaHeadShot.jpg">
<div class="title">Cola the Yorkie BAD</div>
<div>Inline containing a block element. This is bad!</div>
</a>

Inline in Block Element
<a href="#">
<img src="./captainColaHeadShot.jpg">
<span class="title">Cola the Yorkie GOOD</span>
<span>Inline containing an inline element. This is good!</span>
</a>
So, what's the big deal? After all, it works. Well, sort of.

You'll need a couple of things to see what I mean. First, you'll need to run the example in Firefox 2.x or 3.x, but before you do that make sure you've installed Firebug. Now, using Firebug, inspect and edit the text "Inline containing a block element. This is bad!" that's found in the div. Just type in some additional text like "Hello world!" or just anything. Now, inspect the div. You'll notice that the text is now contained inside an anchor tag which is inside the div! What happened?

I'm not sure, but I think Firefox attempts to correct the HTML by putting an inline inside a block-level element ( here's a really good writeup on invalid markup funkiness among the browsers ). If you try the same thing ( editing the text for "Inline containing a block element. This is good!" ), you won't observe this problem. This is because the markup is correct -- we've got a block-level element containing an inline element.

So, in my real job I saw this funkiness happen. Every once in a blue moon on page refresh, the text would be found in an mysterious anchor tag creating an ugly "blown" up visual. Correcting the markup fixed this problem for good.

You might be wondering what's the difference between a block-level element ( <div> ) and using CSS to make an inline element a block-level element ( <span style="display:block;"> ).

If an element by default -- like a div -- is a block-level element then it cannot be placed inside an inline element. However, an inline element made into a block-level element via CSS can be placed inside an inline element. This is because the style that's applied is irrelevant to the correctness of the markup. In other words, styling is our stated intention for what the element should look like and that's completely separate from valid markup.

Have fun!

5 comments:

Anonymous said...

Thanks. Wonderful explanation. Helped me really understand the usefulness of span tags

Anonymous said...

Dude this was very very helpfull. I am a designer and used to care about valid markup, but lately have been ignoring stuff (bad i know.).

I ran into this problem just as you did and was stunned with firefox results and what showed up in firebug. I tried many many things but it was hard to debug, because firefox did it's own auto-misscorrection-magic to just one of the elements out of many.

Now i finally understand why. I had a paragraph element inside a link.

skypoet said...

I hope it was helpful. This kind of stuff can bite in the most unexpected of ways!

Unknown said...

Thank you.
I was trying to make a link like your Cola the Yorkie and the validator bit me.
Yet my problem is that the unstyled text is piled up in an ugly string.
Any suggestion?

skypoet said...

Hi Gabriel,

I'm not sure. Can you post some code? Thank you.