The difference between "The Flow" and "Positioning" for Web Pages

Guest Author: "Big John" Gallant
positioniseverything.net

Return to vision.to

Two very common terms heard in web design circles are "the flow" and "positioning," but what exactly are these concepts and how do they differ from each other? Read on and learn the basic ways they work and interact on a typical HTML page.

Tables and what came before them

Originally the table element was created to provide a visual grid of cells to contain and display tabular data like scientific findings. When the web started to expand there was a need for better designs, and tables became the primary tool for more complex layouts, used to hold and organize sliced-up layout images that produced prettier pages. Sometimes these layout tables were nested together in very complex ways, causing problems for screen readers and search engines.

Before that tho came a simpler type of layout called "The  Flow." The flow still operates on every HTML page so it's a good idea to fully understand how it works. First, be aware that all normally flowed page elements are assumed to have a position property value of static, but you don't need to assign this value, it's the default. Further, when an element is static it's usually described as "unpositioned" even tho all elements technically do have a position value. When an element is termed "positioned" it typically means that it has a position value of absolute, relative or fixed. Don't make the common error of confusing "static" with "fixed."

So all flowed elements are usually statically positioned, altho sometimes they are instead positioned as "relative", a situation we'll be covering later in the article. For now just assume that the flowed elements are at the default static value and don't worry about it.

Block vs. Inline

Altho it's called THE flow, there are actually two kinds of flow: Block and Inline. Generally page elements are said to be "block elements" or "inline elements" but never both at once. These are radically different types of display and each has its specific uses. In the CSS specs both element types may be assigned a position value, but in practice it's best not to try positioning inline elements due to inconsistent behavior in Internet Explorer. This situation should eventually improve along with advances in IE's browser engine.

Block Flow

This type of flowing is not complicated. All block elements are by default just as wide as the container surrounding them, and they always stack up vertically, one atop another, unless you alter the arrangement by forcing them out of their normal locations via relative shifting or negative margining. (We'll get to that, hang on)

Graphic 1
The paragraphs are block, and are displayed in a simple vertical arrangement with full width on all of them by default.

Graphic 2
Block paragraphs don't care about their widths; they always want to occupy their own horizontal space in the flow.

Graphic 1 shows how a series of block elements stack vertically. This remains true even if their widths are made less than the natural width of their containing element. Block elements include paragraphs, divs, lists, and a number of others. This handy listing indicates which elements are block and which are inline. Tables are an exception tho, in that they do stack vertically but don't automatically widen to fill a containing element. Instead they "shrink-to-fit" around their internal content, so if you want them to act like other block elements you must assign them a width of 100%. Be careful tho, because in that case any side borders or paddings will be added to that 100% width, unlike natural block elements which have a default width of "auto".

Graphic 2 shows the same paragraphs, but now they have all been given reduced widths and alternate paragraphs have large left margins to push them to the right. Note how despite being apparently separate vertically, they still all start new lines and don't sit side by side.

If you position or float two or more containing elements side by side, each can have its own flow, completely separate from all other flow contexts. In fact, table cells each have a little flow inside, and the table as a whole is flowed along with any block elements that precede or follow it.

Inline Flow

While all block elements start on a new line, inline elements usually stay on the same line as any inline elements that directly precede them. Most inline elements are simple text characters, but many actual tagged elements (<img>, <span>, <em>, etc) are also inline.

Graphic 3
Both text and images are inline, and line up on an invisible baseline created by the browser. Note: the line boxes normally touch, but these are separated in the graphic for clarity.

Inline elements stack sideways, starting from the left and extending to the right as each new inline element is read by the browser. When the available horizontal space within the containing element is no longer wide enough to hold the next inline element, that element is dropped to a new line and moved to the far left end of the containing block, repeating the process. Be aware that some languages are read right-to-left, and CSS does have special properties to reverse the normal LTR inline flow direction to RTL for those cases.

When a browser runs out of inline elements for a given line, or when it needs to make a new line, the heights of all the elements in the line being formed are measured. Then a "line box" is created that is the same height as the tallest measured element, and the line box is wrapped around them all. This line box is never visible, but you may get an idea of where it is by applying a background-color to a span element that wraps a set of inline elements.

Each time the browser creates a line box it is added below the previous one, so line boxes behave much like block elements, altho some of the properies governing them are different. For instance, a text character in a line box does not sit on the bottom of the line box, but instead on something called the baseline which is usually a few pixels above the bottom of the line box. This way characters with "descenders" (like the hook on the bottom of a small "g") have room for those descenders to hang down while allowing the main bodies of the characters to remain aligned.

For more info on text and the CSS properties that modify its display, see Westciv's Text layout properties page.

Things to keep in mind

You cannot specifically create a line box; they are strictly for use by the browser in organizing groups of inline elements. Also, line boxes will always be the full width of whatever container they occupy, even when they hold only one character. There can never be two separate line boxes of different heights side-by-side.

Block elements may contain both inline elements and other block elements, but inline elements may contain only other inline elements. It's illegal to place a block element inside an inline element like this:

<span><div>some content...</div></span>

CSS features a property called display, which allows you to change a block element into an inline one and vice versa. This can be very useful, but be aware that while making a paragraph inline does cause it to act like a span, it doesn't make it legal to place that paragraph inside a span! You could get away with it in modern browsers but it won't validate. The display property accepts several other values besides "block" and "inline", and a particularly useful value is none, often used to temporarily hide elements on a page, to be revealed later.

Here's more on the subject of display.

Block boxes are always rectangles and can be given widths and heights, but inline elements ignore those properties, since they must occupy an unknown set of line boxes. Both block and inline elements can have padding and margins, but using these on inline elements might show inconsistent results across browsers, and in any case only the side paddings and margins are obeyed for inline elements.

If you think about it you will see why this must be so. If a span did obey vertical paddings for instance, then the lines above and below would be pushed away. When the specs were made it was decided that this was not desirable, thus top and bottom paddings and margins are ignored for inline elements, as shown in the two live demos with the colored borders. The word "paddings" above has been wrapped in a span that has a red border and 2em of padding, and the word "margins" has similar margins and a green border. You can see how only the side paddings and margins are obeyed, while the vertical ones are ignored.

Positioned Elements

Positioning elements can be useful and fun too, but it's quite different than the flow. Let's start with relative positioning, since it's not too different than static positioning.

Relative Positioning

While relatively positioned elements are considered to be positioned, they actually flow just like static elements do. If you write the code below, nothing is visually different than if you didn't position that fourth paragraph:

<p>Paragraph</p> <p>Paragraph</p> <p>Paragraph</p> <p style="position: relative;">Paragraph</p> <p>Paragraph</p> <p>Paragraph</p> <p>Paragraph</p> <p>Paragraph</p>

However, things have changed for that paragraph, because now we are able to "shift" it in any direction we like without altering any other elements' page placement. Without shifting, the paragraphs will simply stack up vertically, even the relative one.

Let's try adding pixel values for the CSS properties left and top, applying them to that relative paragraph:

<p>Paragraph</p> <p>Paragraph</p> <p>Paragraph</p> <p style="position: relative; left: 20px; top: -20px;">Paragraph</p> <p>Paragraph</p> <p>Paragraph</p> <p>Paragraph</p> <p>Paragraph</p>

Graphic 4
The paragraphs are displayed normally except that the relatively shifted one is raised to a new level and moved sideways out of its normally flowed position.

Note that the left value is positive and shifts the paragraph away from the left edge of the parent container, while the top value is negative and shifts the paragraph toward the top edge of the parent. I could just as easily have used a positive bottom value or negative right value for the same results, but if (for instance) a top value also exists on the same relative element it can override your bottom value, possibly causing confusion. This can be avoided by sticking with just the left and top properties, applying positive or negative values to them as needed.

Also note that relative shifting of an element leaves behind a "hole" the same size as the element, while the shifted element gets raised to a separate level and slides across the page without affecting other elements.

This shifty business is best used sparingly for minor page adjustments and not for major layout functions, due to some bugs that can occur for very large relative elements. When you do use relative shifting be sure to carefully test in several browsers.

Relative positioning also has other uses which we'll cover shortly.

Absolute Positioning

This type of positioning makes elements behave in radically different ways than normally flowed elements. Most importantly, every absolutely positioned (AP) element occupies a unique layer or z-index level from all other elements, even other AP elements. This means that an AP element never touches another element, but it can easily cover or be covered by various elements. This layering is normally handled by the browser by placing AP elements which come last in the source "in front of" or closer to the viewer than earlier elements.

By default, absolutely positioned (AP) elements shrink-to-fit their widths (and heights) around any internal content they may hold. If that internal content is an image, the surrounding AP element will become the same width and height as the image, unless you explicitly control those dimensions.

This was not always the case tho, and at one time the specs said that AP elements should be full-width by default. Microsoft disagreed with this idea, and all their CSS-able browser versions displayed the shrink-to-fit behavior from the start. This AP behavior was so obviously superior that eventually all the other browsers adopted the behavior and the specs got changed to reflect this. Just be aware that some old non-IE browsers can display AP elements wider than they appear in modern browsers.

To repeat, absolutely positioned elements are not part of any flow. Instead, an AP element is always located in reference to some parent element using horizontal and vertical coordinates. But which parent? If the AP element's direct parent is not itself "positioned" (meaning any position other than static) then the inner AP element does not use that direct parent as its base of reference. Instead it will look further out until it finds an "ancestor" that is positioned and uses that as its base. If no such positioned ancestor exist, the HTML element is the default positioned parent. An element is considered to be an ancestor of all other elements that fall between its start and end tags.

When that AP child references its nearest positioned parent as a base, it first finds the locations of the parent's sides and then offsets itself from two (or more) of those sides, depending on its current values for the properties left, top, right and bottom. These are all set to "auto" by default, so if any of them are changed to some length value, that length becomes dominant and overrides the auto value on the opposite side.

This mainly occurs when the AP child has dimensions set on it. For example, say you give an AP element a width that is less than the width of its positioned parent, and then set the right property on the AP child to "10px". This value takes over and moves the right edge of the AP child to the right edge of the positioned parent, then offsets it inward, away from that side by 10px.

Be aware tho that if you try to set both the left and right properties this way, one of then must be ignored because the AP child has a rigid width. In that case it's the left value that wins. Similarly the top property can win over the bottom property when there is a conflict between them. However, should the AP child have no width assigned to it, both the left and right properties can be obeyed, which actually controls the displayed width of the box! The same goes for the top and bottom properties.

Unfortunately IE6 is unable to handle this last trick and will just make the AP child shrink-to-fit around any content it holds. IE7 does the trick correctly, so if you decide you want to dumb down IE6 via special IE6-only CSS, you will be free to size AP elements using only the side-controlling properties.

Auto Positioning

There is one exception to the "positioned parent" rule, and that is when the horizontal or vertical positioning properties are allowed to remain at the default "auto" value. If both the left and right properties are auto, the AP element will locate itself horizontally as if it were a static element. Thus if a static flowed box were normally displayed halfway across the page width, an AP box with side auto values and the same source location would also display at that page location. This does not mean that the AP element is now in the flow; it's still on its own separate layer. Only its displayed location is controlled by the flow. Any flowed elements that follow it will display without noticing the presence of the AP element, and they can sometimes be covered by that AP element. The same thing applies to AP elements with auto top and bottom values, but vertically rather horizontally.

I call this effect "auto positioning" but it really just means absolute positioning that is controlled by the flow via auto side values. It's a bit tricky and will be covered in a later article. To avoid the issue just be sure to always use at least two side positional vaues (preferably left and top) when placing AP elements.

Changing the stacking order

Let's look at two simple AP divs with default z-index stacking:

<div style="position: absolute;">AP One</div> <div style="position: absolute; left: 20px; top: 20px;">AP Two</div>

Graphic 5
The first AP div is covered by the second AP div by default.

AP div two comes later in the source, so it gets a larger z-index number from the browser. This default stacking order for positioned elements may be overridden via direct control of the z-index property, which works on all absolute, relative and fixed elements. (more on fixed positioning in a moment)

<div style="position: absolute; z-index: 2;">AP One</div> <div style="position: absolute; left: 20px; top: 20px; z-index: 1;">AP Two</div>

Graphic 6
The second AP div is now covered by the first AP div.

Note that even relative elements that are in the flow do have a z-index value. IE6 has an infamous bug that wrongly allows an AP element with a lower z-index number to overlap a relative element with a higher z-index number. This cannot be fixed, so if it occurs you will need to work around it.

Be aware that you do not need to assign z-index numbers in a precise order. As long as one positioned elements' z-index is higher than another's, the higher one will overlap the lower one. A useful practice is to assign z-index numbers in jumps of 10 or 100 (100, 200, 300, etc...) so that later on you can add more AP elements between these levels without having to rework the entire numbering system.

Mysterious broken links caused by AP elements

A common problem in web design happens when links are somehow "unclickable" in most browsers, but not in IE browsers. This usually is the result of a transparent AP element which covers those links. The specs say that you can't click thru any element, transparent or not, but IE7 and below do allow this kind of link clicking. If IE links do click and others don't, look for some AP element covering the links and rearrange things so the overlap does not happen.

Relative Base, Absolute Child

Graphic 7
An AP child may calculate its location based on the sides of a relatively positioned and flowed ancestor.

Relatively positioned elements have another function besides being able to shift around, and that is to serve as a "positioned base" for AP elements. See what this means? Relative elements do participate in the flow, yet they may also provide a positioned base that AP children can use to calculate their own locations. That's why it's called "relative positioning," because those elements relate and join the world of the flow to the world of absolute positioning.

Graphic 7 shows a possible arrangement of elements, with an AP child basing its location on a flowed relative parent. Modern CSS layout sometimes make heavy use of this technique, so you would be wise to experiment and become comfortable with it.

Be aware that IE6 may have trouble with the method unless the relative parent is given hasLayout via the zoom fix.

Fixed Positioning

Many people confuse static and fixed elements. Fixed positioning is really just a subset of absolute positioning, except that fixed elements always consider the viewport itself to be the base. Since the viewport never scrolls, neither do fixed elements. This causes fixed elements to be a bit tricky to handle.

First, fixed elements, unless carefully placed and sized, can easily be made to extend outside the bounds of the viewport. It's true that other types of element can do this too, but they will then create scrollbars for access purposes. At least they do when they extend downward and/or to the right of the viewport edges. Remember tho that fixed elements are controlled by the viewport and never scroll, so there's no good reason they should scrollbars, and they don't ever do so. Such scrollbars might scroll all other elements, but not fixed elements!

However, fixed elements arre allowed to internally scroll contained content, assuming you limit dimensions on the fixed box and force scrolling via the overflow property.

Fixed positioning is primarily meant to replace frames and all the problems that frames cause. Unfortunately IE6 did not support fixed positioning, altho there are tricky methods to make IE6 simulate fixed positioning. I don't recommend those methods because they put limits on certain kinds of layouts and they aren't very simple to implement. It's better to just let IE7 do it right and then dumb down IE6 to plain old absolute positioning, which does work fine in all browsers.

That's it for this article; Be sure to check out the next one on auto positioning too.