Thursday, August 19, 2004

Blocks by default STACK

I'm not sure why people have such a hard time understanding that blocks by default stack on top of each other. I'm not sure why this is such a difficult concept, it's been happening since day one of your introduction to HTML class.

First this question manifests itself in three situations: How do I get my footer div below everything else?, Why doesn't this block sit along side another block? and How come my outer div's background doesn't cover up the whole area of the two inner divs?. They are several seemingly different questions with usually one root cause: blocks, by default, stack. The questions might never arise, except that someone has done something that changes a block's default behavior.

It's probably a good idea to define a few terms. Stack means that the two elements have a vertical relationship which is often visually represented recognized as a line-break which cause the first element to be directly above another. Block refers to a class of HTML elements which stack as compared to those elements which can be used inline. Finally an element is just a generic term for what is generated by an HTML tag.

As I mentioned earlier, everyone is familiar with the fact that block level elements stacking. For example, the code below uses four block level elements: <h1>, <p>, <h2> and another <p>.:

<h1>Lorem ipsum dolor sit amet</h1>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>

<h2>Vivamus cursus iaculis ante</h2>

<p>Vivamus cursus iaculis ante. In id nisl quis tellus suscipit venenatis. Suspendisse potenti.</p>

In the pre-CSS days, everyone seemed to realize that the h1 would be on top of the p which in turn was on top of the h2 which was on top of the final p. Catch that? The implication might be subtle: no matter what content you put between any of the tags, it pushed the subsequent content down the page. In CSS days, guess what! That same logic holds.

Most people take the above for granted. And, in all the confusion, somehow block level elements like headers, lists and paragraphs are different than the div tag. Not that you'd ever do this, but look at this code:

<div>Lorem ipsum dolor sit amet</div>
<div>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div>

<div>Vivamus cursus iaculis ante</div>

<div>Vivamus cursus iaculis ante. In id nisl quis tellus suscipit venenatis. Suspendisse potenti.</div>

Executing the above code renders the following:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Vivamus cursus iaculis ante
Vivamus cursus iaculis ante. In id nisl quis tellus suscipit venenatis. Suspendisse potenti.

Magic, isn't it? Need some proof, use the border property. The single greatest CSS development trick is to just start adding borders. If we apply a thin border to each div, we can see how they stack:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Vivamus cursus iaculis ante
Vivamus cursus iaculis ante. In id nisl quis tellus suscipit venenatis. Suspendisse potenti.

As you can see, the borders wrap the content of all the elements. In addition, the borders consume, by default, all the horizontal space. Finally, without any margins, each border touches the subsequent border.

I imagine the first problem of How do I get my block at the bottom occurs for two reasons:

  1. One of the middle elements has been removed from the document flow
  2. The developer is using absolute positioning to try to place things on the page.

In fact, point two is actually a special case of the first. Absolute positioning has it's place, but it, to the extreme, removes an element from the document flow and non-child elements have no way of interacting with it.

Document flow

Document flow is the term used to describe how elements, by default, render to the viewport. The default document flow is what was discussed and illustrated earlier. There are two common properties, however, which trap beginner CSS developers of altering the default document flow: float and position.

Position: absolute; in particular totally removes an element. Using position absolute on the first div above cause the subsequent blocks to ignore it and they begin to overlap.:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Vivamus cursus iaculis ante
Vivamus cursus iaculis ante. In id nisl quis tellus suscipit venenatis. Suspendisse potenti.

When the content of the first div grows and expands, the subsequent divs ignore it and continue to overlap. The only way to avoid overlapping is to start throwing in code that works around it: ie. margins and or pixel offsets. This becomes very messy, very quickly. It is also probably one of the areas of greatest frustration.

More often than not though, developers mess with the document flow by using the float property. The float property alters the default stacking behavior. For example, if you want the first and third (ostensibly our headers from the first example) to be along the left hand side of the paragraphs you might add: float: left;:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Vivamus cursus iaculis ante
Vivamus cursus iaculis ante. In id nisl quis tellus suscipit venenatis. Suspendisse potenti.

You should note a few things. First, float left alone won't do much if you have a great deal of content in your headers. This is because there is nothing telling the blocks to behave other than to attempt to consume all the horizontal space. The float property alters this behavior a little. You'll notice that the borders do not extend all the way, but rather closely surround the content. If we wanted to achieve a column like effect, simply add a width.

The second thing you'll note is that even where the non-floated blocks did align along side, their borders extended behind the floats. This is because they've been removed from the document flow. Floating blocks alter the location of text, but do not interfere with other block level element features including: backgrounds, borders, margins, and padding.

Despite the floated elements, note how the second and fourth blocks still stack on top of each other. However, if the floated blocks had a width and the "column" becomes longer than the content situated next to it, we begin down the journey of unwanted results.

While beginners are quick to pick up the importance of float, they often overlook float's kryptonite: clear. The clear property causes blocks to not sit next to floated blocks. If we apply clear: left; to the second and fourth blocks in the previous example we get the following results:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Vivamus cursus iaculis ante
Vivamus cursus iaculis ante. In id nisl quis tellus suscipit venenatis. Suspendisse potenti.

Notice the nice stacking! The clear canceled the effects of floating.

A containing div

What is not obvious from the previous examples is that since floating blocks and positioning blocks absolutely remove those blocks from the document flow, they do not alter the height of a container. This is probably the source of the third problem. Below is an example of the default behavior of two divs towards a containing div:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

By default the containing green border wraps both of the two inner divs. This is usually what the developer expects to happen. However, like always this changes when the document flow is altered. Consider the two divs with float: left; width: 25%;:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

Here, notice that the green border does not wrap the two inner divs (if they do, get a better browser). This is the quintessential Containing Floats problem. One that has a number of solutions, even one that I published here about using :after pseudo-class to clear floats.

Altering width doesn't change block behavior

Finally, as sort of an after-thought, altering the width alone does nothing to change a block's behavior. Above we saw how adding float: left; to a block made subsequent blocks align along side it. One common trap for starting developer's is their belief that simply by making a block's width less than 100%, things should line up next to them.

There is, admittedly, some logic to this thought process. However, notice what happens when the first block is given a width of 25% without a float:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

The second block, no matter what still attempts to consume all the available horizontal space. We can fix that by adding width: 25% to the second block:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

Even though their widths are less than 100% (by alot mind you), they still do not site next to each other. The problem is that we've forgotten a block's default behavior. Since a block's default behavior is to stack we need to alter it. As above, this is most often achieved using the float property.

In conclusion

Remember that blocks stack. You knew it before you read this, and you should definitely understand it now. Getting page elements to flow with changes shouldn't be a problem anymore.

1 Comments:

At 3:32 AM, Blogger Anonymous said...

Thanks for the in depth explanation!

 

Post a Comment

<< Home