Sue Ledoux
Developer Technology Engineer
Microsoft Corporation
August 12, 1998
Contents
Introduction
Overview of Properties
Position Property
Visibility Property
Clip Property
Overflow Property
Z-Index Property
Dynamic Positioning
Don't Forget to Test
Conclusion
You may also have heard the term "CSS positioning." If you're like me, you may have wondered not only what it is, but what its relationship is with CSS. Is CSS positioning just another part of CSS, or is it something special? The answer is both. To explain how CSS positioning fits in with CSS in general, let's have a look at the categories of properties found in CSS:
Table 1. Categories of CSS Properties
Category | Description |
Font | Typography properties |
Color and Background | Color of text and background, and background image properties |
Text | Text alignment, spacing, and formatting |
Box | Box formatting properties |
Classification | Display and list properties |
Positioning | Positioning and flow control of elements |
Printing | Page break specification |
Filter | Multimedia effects and transitions |
Pseudo-Classes and Other Properties | The @import, cursor, and !important properties |
As you can see, positioning is just one sub-category of properties available within CSS. However, because it is one of the most powerful, important, and useful aspects of CSS, it has acquired its own informal name. Indeed, the W3C addresses CSS positioning in an entirely separate specification, entitled Positioning HTML Elements with Cascading Style Sheets . It is currently in Working Draft status, meaning that not all of the functionality has been finalized. This article focuses on the information found in that document.
That document gives complete and detailed information about CSS positioning. If you have already read and thoroughly understood it, you probably won't need to continue with this article. And furthermore, you should be proud of yourself! CSS positioning is a powerful and flexible set of features, and it was obviously architected by some smart people. And characteristically, when smart people get together and write a specification, they don't always explain things at a level suitable for some us more ordinary humans.
When I set out to learn about positioning, I found that I had to read the specification several times through and then create some of my own test pages before I fully understood it (particularly how the position property affects the placement of elements and flow of the document). So I decided it might be nice to try to explain the subject in lighter terms, more suitable for those newer to HTML and CSS authoring. A secondary goal of this article is that we feel that CSS positioning is a particularly useful and powerful feature set of Internet Explorer 4.0, and it is worth calling special attention to it.
In order for this article to be useful, it's important that you have a basic understanding of HTML authoring. And although you can probably understand what's going on in the article without much knowledge of CSS, you'll want to be familiar with all of CSS before you begin authoring your own Web pages. Information about CSS can be found in the DHTML, HTML & CSS section of the MSDN Online (SBN) Workshop, and in the W3C recommendation for Cascading Style Sheets, level 1 .
Table 2. CSS Positioning Properties
Property | Description | Possible values | Applies To |
position | Makes elements positionable | absolute | relative | static | All elements |
left | Left position of element | length | percentage | auto | Absolutely and relatively positioned elements |
top | Top position of element | length | percentage | auto | Absolutely and relatively positioned elements |
height | Height of element | length | auto | DIV, SPAN and replaced elements |
width | Width of element | length | percentage | auto | DIV, SPAN and replaced elements |
visibility | Controls visibility | visible | hidden | inherit | All elements |
z-index | Layering control | auto | integer | Absolutely and relatively positioned elements |
clip | Defines visible area of element | shape | auto | All elements |
overflow | Specifies behavior on overflow | visible | hidden | scroll | auto | All elements |
Before we go into details of the individual properties, let's get some terminology out of the way.
How some of the properties are implemented depends on the hierarchical relationships between elements. For our purposes, the <BODY> tag is at the top of the hierarchy for a given HTML document. An element is the child of another element if it is nested within the tag of another element. The enclosing element is called the parent element. A sibling of an element is one that shares a parent. And the previous element refers to the element that immediately precedes an element in the source file, regardless of whether it has a parent, sibling, or no relationship.
The origin for a given element is where the 0,0 coordinate pair is located, from which the top and left properties are offset (we'll go into detail about this later). Each element has its own origin, which depends on the value of its position property as well as its location within the hierarchy of elements.
The flow of the document refers to the natural way the content "flows" into the browser window, which may or may not change (depending on the values of certain properties) as the browser window is resized.
Calculating where an absolutely positioned element will be rendered is fairly straightforward. Absolutely positioned elements and their children are not part of the regular flow of the document, but are positioned independently, possibly overlapping other elements.
To calculate the origin of an absolutely positioned element, find the next parent element that is positioned either relatively or absolutely (that is, if a parent is static, skip it and go up the hierarchical chain to the next parent. If the <BODY> tag is reached, the traversal stops and it will be considered the parent element regardless of the value of its position property). The logical beginning of this parent element is the origin for the absolutely positioned element. That origin may or may not move as the window is resized, but the element will always be in the same place with respect to that origin.
The origin establishes the top left corner of a rectangle into which the absolutely positioned element and its children will flow. These three samples demonstrate the origin calculation for an absolutely positioned element. I've pulled out the relevant lines of code, and you can click on the link to run the sample.
Please note that you need to view this article's samples using Internet Explorer 4.0 or later.
Sample 1: Absolutely positioned element with statically positioned parent
<SPAN STYLE="position:static; background-color:#90EE90">static green parent static green parent static green parent static green parent <SPAN STYLE="position:absolute; top:60px; left:60px; background-color:#ADD8E6">absolute blue child absolute blue child absolute blue child absolute blue child</SPAN> </SPAN>
Sample 2: Absolutely positioned element with relatively positioned parent
<SPAN STYLE="position:relative; background-color:#90EE90">relative green parent relative green parent relative green parent relative green parent <SPAN STYLE="position:absolute; top:60px; left:60px; background-color:#ADD8E6">absolute blue child absolute blue child absolute blue child absolute blue child</SPAN> </SPAN>
Sample 3: Absolutely positioned element with absolutely positioned parent
<SPAN STYLE="position:absolute; background-color:#90EE90">absolute green parent absolute green parent absolute green parent absolute green parent <SPAN STYLE="position:absolute; top:60px; left:60px; background-color:#ADD8E6">absolute blue child absolute blue child absolute blue child absolute blue child</SPAN> </SPAN>
In the first sample, because the parent is statically positioned, we "ignore" this and look to the next element in the hierarchy. In this case it's the BODY element, so we use the beginning of the BODY (that is, the beginning of the document) as the origin. In the other two examples, the parents of the absolutely positioned blue element are relatively and absolutely positioned, so they are used to establish the origin. So the blue text is positioned in the same place in the second and third examples (60 pixels below the top of the green element), which is slightly lower than in the first one (60 pixels lower than the top of the BODY element). In all three cases, the blue text is absolutely positioned, so no matter how you resize the window to make the green text flow, the blue text begins at the same location, and will overwrite the green text if necessary.
The way that the top and left properties are used also helps determine where an absolutely positioned element is positioned. If the element has its top and left properties set, the element will be positioned using these offsets with respect to the origin that we just talked about. If the top property is omitted or is set to auto (which is equivalent because auto is the default), the element will have its top edge beginning at the top of the last line of text of the parent element if it's text, and lined up with the top edge of the parent if it's an image. If the left property is omitted, the element will have its left edge positioned at the end of the last line of text of the parent element if it's text, and at the right edge of the parent if it's an image.
Following are four samples that demonstrate this. Be sure to resize the windows to see how changing a parent's position affects its absolutely positioned child. You can substitute the "relative green parent" text with an image to see the behavior when the parent is an image.
Sample 4: Absolutely positioned element with neither top nor left set
<SPAN STYLE="position:relative; background-color:#90EE90">relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent <SPAN STYLE="position:absolute; background-color:#ADD8E6">Absolute blue child with neither top nor left set.</SPAN> </SPAN>
In Sample 4, because neither top nor left are set, the origin of the blue element is at the end of the green one. However, because the green element reflows when the browser window changes, this origin can actually move around. You'll see how this works if you make the browser window progressively narrower and watch the blue text.
Sample 5: Absolutely positioned element with top and left set
<SPAN STYLE="position:relative; background-color:#90EE90">relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent <SPAN STYLE="position:absolute; top:10px; left:50px; background-color:#ADD8E6">Absolute blue child with top:10px and left:50px.</SPAN> </SPAN>
In Sample 5, because both the top and left are set, the origin for the blue element never moves no matter how narrow you make the browser window.
Sample 6: Absolutely positioned element with just top set
<SPAN STYLE="position:relative; background-color:#90EE90">relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent <SPAN STYLE="position:absolute; top:10px; background-color:#ADD8E6">Absolute blue child with top:10px.</SPAN> </SPAN>
In Sample 6 we've got only the top set. So, according to the rules, that means the top value of the origin will never move -- the blue element will always begin 10 pixels from the top of its (non-static) parent, the green element. But the left value for the origin is set to auto (by default, because it's not set at all), meaning to the end of the parent (green) element, so you'll see the left edge of the blue element's rectangle move as you make the browser window narrower.
Sample 7: Absolutely positioned element with just left set
<SPAN STYLE="position:relative; background-color:#90EE90">relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent relative green parent <SPAN STYLE="position:absolute; left:50px; background-color:#ADD8E6">Absolute blue child with left:50px.</SPAN> </SPAN>
Sample 7 is just the reverse of Sample 6; in this case, the left side of the blue element's rectangle remains constant at 50 pixels, while the top varies depending on where the end of the green parent element is.
As we've already mentioned, the absolutely positioned element defines a new rectangle into which it and all of its children flow (and will draw over the top of other elements if necessary). The box begins at the top left corner of the element. You can set the width and height properties for the element. If no width property is defined, the rectangle to will extend to the right edge of the browser window. If a width is defined, it will retain that width even if the rectangle extends beyond the browser window; that part of the contents will therefore be obscured. If no height property is defined, the rectangle will extend as far down as necessary to display all of the contents. (Note that these descriptions for what happens when either the width or height properties are not defined represent default behavior; this behavior can be changed by setting the overflow property, which is discussed later).
Sample 8: Absolutely positioned element with no width or height defined
<SPAN STYLE="position:relative; background-color:#90EE90">Relative green parent. <SPAN STYLE="position:absolute; top:50px; left:50px; background-color:#ADD8E6">absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child </SPAN> </SPAN>
Sample 8 shows an absolutely positioned element without width or height defined. You can see as you make the browser window narrower that the rectangle into which the blue element flows always extends to the right edge of the browser window, reflowing downward if necessary.
Sample 9: Absolutely positioned element with width defined
<SPAN STYLE="position:relative; background-color:#90EE90">Relative green parent. <SPAN STYLE="position:absolute; top:50px; left:50px; width:200px; background-color:#ADD8E6">absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child </SPAN> </SPAN>
Sample 9 demonstrates the use of the width property. In this case, the width of the blue element's rectangle remains the same regardless of the width of the browser.
We talked before about how absolutely positioned elements and their children were not part of the regular flow, but instead create their own rectangle. Sample 10 demonstrates this. The blue absolutely positioned element defines the origin of its rectangle to be at 50,50 and the width at 250 pixels. Since no height is set, the rectangle extends down as far down as necessary. The blue element has a red relatively positioned child, and you'll see that this child flows after the blue element but entirely within the left and right boundaries of the defined rectangle.
Sample 10: Absolutely positioned element with relatively positioned child
<SPAN STYLE="position:relative; background-color:#90EE90">Relative green parent. <SPAN STYLE="position:absolute; top:50px; left:50px; width:250px; background-color:#ADD8E6">absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child absolute blue child <SPAN STYLE="position:relative; background-color:#FFB6C1">relative red child relative red child relative red child relative red child relative red child relative red child relative red child </SPAN> </SPAN> </SPAN>
Figuring out where relatively positioned elements will end up is a little trickier. Relatively and statically positioned elements form the flow of elements in a document (as opposed to absolutely positioned elements, which are positioned as if on a layer above the other elements). To figure out what the flow of elements looks like, look through the source file, and mentally remove all absolutely positioned elements, including any children of those elements. Then position the remaining relatively positioned elements one after another -- this is because for a relatively positioned element, the origin for element is at the end of the previous element in the flow (not in the source file), regardless of the hierarchical relationship.
Relatively positioned elements that are children of absolutely positioned elements were "removed" from the flow as explained above; they are still placed after the end of the previous element in the source, except that they are now relative to an absolutely positioned element that can be at any arbitrary place.
This is not easy to explain, but the examples should make it more clear. Samples 11, 12, and 13 all display identically. Because all are relatively positioned elements with no top or left properties set, they simply flow one after another, regardless of their hierarchical relationship with each other.
Sample 11: Three same-level relatively positioned elements
<SPAN STYLE="position:relative; background-color:#90EE90">Green relative element.</SPAN> <SPAN STYLE="position:relative; background-color:#ADD8E6">Blue relative element.</SPAN> <SPAN STYLE="position:relative; background-color:#FFB6C1">Red relative element.</SPAN>
Sample 12: Three nested relatively positioned elements
<SPAN STYLE="position:relative; background-color:#90EE90">Green relative element. <SPAN STYLE="position:relative; background-color:#ADD8E6">Blue relative child of green. <SPAN STYLE="position:relative; background-color:#FFB6C1">Red relative child of blue. </SPAN> </SPAN> </SPAN>
Sample 13: Three relatively positioned elements; the second is a child of the first
<SPAN STYLE="position:relative; background-color:#90EE90">Green relative element. <SPAN STYLE="position:relative; background-color:#ADD8E6">Blue relative child of green.</SPAN> </SPAN> <SPAN STYLE="position:relative; background-color:#FFB6C1">Red relative element.</SPAN>
Sample 14 demonstrates how absolutely positioned elements are not part of the document flow. Even though the blue element is between the two relatively positioned elements in the source file, it does not affect the flow of the document. No matter how the window is resized, the blue element begins at the same location, and the red element flows directly after the green one.
Sample 14: Relative, absolute, relative
<SPAN STYLE="position:relative; background-color:#90EE90">green relative element green relative element green relative element</SPAN> <SPAN STYLE="position:absolute; top:50px; left:50px; background-color:#ADD8E6">Blue absolute element with top:50px and left:50px.</SPAN> <SPAN STYLE="position:relative; background-color:#FFB6C1">red relative element red relative element red relative element</SPAN>
Sample 15 is similar except that the absolutely positioned blue element has a child. As you can see, the blue element and its child are pulled out of the flow of the document, while the red element again follows the green one.
Sample 15: Relative, absolute with relative child, relative
<SPAN STYLE="position:relative; background-color:#90EE90">green relative element green relative element green relative element</SPAN> <SPAN STYLE="position:absolute; top:50px; left:50px; background-color:#ADD8E6">Blue absolute element with top:50px and left:50px. <SPAN STYLE="position:relative; background-color:#FFFFFF">White relative child of blue.</SPAN> </SPAN> <SPAN STYLE="position:relative; background-color:#FFB6C1">red relative element red relative element red relative element</SPAN>Now, when we start setting the top and left properties of the relatively positioned elements, things get even more interesting. Let's say we have a relatively positioned element that has its top and/or left properties set. Another relatively positioned element that directly follows it in the flow calculates its origin as follows:
Sample 16: Three same-level relatively positioned elements
<SPAN STYLE="position:relative; background-color:#90EE90">Green relative element.</SPAN> <SPAN STYLE="position:relative; top:20px; background-color:#ADD8E6">Blue relative element with top:20px.</SPAN> <SPAN STYLE="position:relative; background-color:#FFB6C1">Red relative element.</SPAN>
In Sample 16, the blue element is offset 20 pixels from the top of where it would have been. Because the following red element is not a child of the blue element, it is drawn at the end of where the blue element would have been, had we not adjusted its position using the top property.
Sample 17: Three nested relatively positioned elements
<SPAN STYLE="position:relative; background-color:#90EE90">Green relative element. <SPAN STYLE="position:relative; top:20px; background-color:#ADD8E6">Blue relative child of green with top:20px. <SPAN STYLE="position:relative; background-color:#FFB6C1">Red relative child of blue. </SPAN> </SPAN> </SPAN>
Sample 17 shows what happens now that the red element is a child of the blue; the position of the blue element has been altered, and the red element is drawn at the end of where the blue element now is.
We already discussed how statically positioned elements are ignored when calculating the origin for absolutely positioned elements. When mixed in with relatively positioned elements, statically positioned elements take the same origin as a relatively positioned element would; the primary difference is that you cannot set or offset the position of a statically positioned element using the top and left properties. A common mistake is to attempt to set these properties without first setting the position property to absolute or relative, (because the default for the position property is static) and then wonder why they have no effect. And because the top and left properties are meaningless when position is static, it follows that, as their name implies, a statically positioned element cannot have its position altered through script.
Sample 18: Comparison of the visibility and display properties (VBScript)
Sample 18: Comparison of the visibility and display properties (JScript)
On the first image, the button preceding it toggles the visibility property between visible and hidden, while the second button toggles the display property of the second image between none and the null string. (Note that we use the null string here because none is the only value that is currently explicitly supported. While specifying inline or block will appear to work for now, your pages will be rendered differently in the future when these values are supported. Null will always default to the default value, so it will display the element without breaking your code in the future.)
Sample 19: The clip property (VBScript)
Sample 19: The clip property (JScript)
The sample shows the syntax for setting the clip region initially, using an inline style sheet or script (the JavaScript and Visual Basic® Scripting Edition (VBScript) versions are identical except for JavaScript's terminating semicolon). Pay close attention to the order of the parameters: top, right, bottom, left:
Inline style sheet
<IMG ID=Olivia1 STYLE="position:absolute; top:0px; left:0px; width:136px; height:228px; clip:rect(0 136 228 0)" SRC=olivia1.gif>
as well as how to set the clip region in script:
Script
Olivia1.style.clip = "rect(0 136 228 0)"
Sample 20: The overflow property
Each of the four sections uses identical code (except for the positioning), shown below, with only the value of the overflow property changed. I've made the background of the elements white so that you can see how much space the element is utilizing.
<DIV STYLE="position:absolute; top:60px; left:0px; width:100px; height:100px; overflow:visible; background-color:white"> This is short. </DIV> <DIV STYLE="position:absolute; top:60px; left:200px; width:100px; height:100px; overflow:visible; background-color:white"> This is really really really really really really really really really really really long. </DIV>
Sample 21: The z-index property
This property is very straightforward; the sample just shows the syntax and demonstrates the drawing order.
I'll demonstrate the concept of dynamic positioning in a boring moving-text sample. But it should be enough to demonstrate the concept; dynamic positioning is very straightforward to implement. All the same rules that we've already covered about how elements get positioned still apply.
For example, in this sample, the blue text is a sibling of the red text. As we discussed earlier, a sibling is positioned relative to the end of the space the preceding element would have occupied had it not been positioned with the top and left properties. So the blue text stays put while the red text moves.
Sample 22: Animate with siblings (VBScript)
Sample 22: Animate with siblings (JScript)
On the other hand, in this sample, the blue text is a child of the red text. As our rules stated, that means it is supposed to be positioned relative to the actual position of the parent, and sure enough, the blue text faithfully follows the red text around, even though we never explicitly change its position.
Sample 23: Animate with children (VBScript)
Sample 23: Animate with children (JScript)
Let's have a look at the JavaScript version of the Sample 22 (both samples move the text the same way; the only difference is the relationship between the two text elements). The HTML portion of the sample looks like this:
<BODY BGCOLOR=lightgrey onload="StartMove()"> <SPAN ID=MovingText STYLE="position:relative; background-color:#FFB6C1">This text can whiz on and off the page.</SPAN> <SPAN STYLE="position:relative; background-color:#ADD8E6">This text is a sibling of the moving red text.</SPAN> </BODY>
First, note that when we define the text, we set the position property to be relative. Remember, even though we don't want to explicitly position the text, position must be set to relative or absolute to be able to dynamically change the position. In the <BODY> tag we've specified that the StartMove() function should be called when the page is loaded. This function looks like this:
function StartMove() { TextVisible = 1; action = window.setInterval("MoveText()", 50); }
We set a variable called TextVisible to 1 to tell ourselves that the text is currently visible. We just use this variable basically to keep track of which way the text is moving, on or off the page. Then we set a timer to call the MoveText() function every 50 milliseconds.
function MoveText() { if (TextVisible == 0) { MovingText.style.pixelLeft += 10; if (MovingText.style.pixelLeft == 0 ) { TextVisible = 1; } } else { MovingText.style.pixelLeft -= 10; if (MovingText.style.pixelLeft == -240 ) { TextVisible = 0; } } }
Each time this function is called, it checks the value of TextVisible. If it is 0, this means that the string is still not fully on the page and needs to be moved to the right, so it adds 10 pixels to the value of its left position (the pixelLeft property). It then checks to see if we are fully on the page (at which time the pixelLeft value will be 0), and if we are, sets the value of the TextVisible variable to 1. Then in future calls to MoveText(), we subtract 10 pixels from pixelLeft and therefore move the text to the left, off the screen. We keep doing this until we have moved 240 pixels to the left, then set TextVisible to 0 and the whole process will repeat itself infinitely. (Note the use of the pixelLeft property rather than the left property; we need to do this because we're manipulating the value, and left returns the value as a string where pixelLeft is an integer.)
That's all there is to dynamically positioning elements -- just decide what you want to do, think about how it will affect the position of other elements on the page, and change the position according to a timer, a user action, or whatever else meets your needs.
If you have complex positioning needs, you can get as fancy as you like nesting elements and manipulating properties to achieve your goals. Or, if you still find this a little confusing to follow, you can probably do most of what you want to do and understand your code if you keep it simple and don't nest your elements too deeply. Either way, don't forget to view your pages in all sizes of browser windows, from the smallest to the largest, to ensure the results are what you intended.
In the old days, HTML authors had very little control over where elements were placed on the page. The most they could achieve came from complex table code that was difficult to maintain. With CSS positioning, you can now enjoy complete control over positioning, not to mention easy and efficient animation capabilities. A place for everything, and everything in its place.