Chapter 4. Adding Dynamic Positioning to Documents

Cascading style sheets, as described in Chapter 3, are primarily concerned with how content looks on the screen (or how it looks on a page printed from the screen). An extension to CSS, called CSS-Positioning (or CSS-P), is primarily concerned with where content appears on the page. CSS-P is blended with regular CSS in the CSS2 specification, but because the Version 4 browsers were designed while positioning was a separate standards effort, I use the CSS-P term frequently.

The CSS-P recommendation from the W3C focuses on the HTML code that authors put into documents to govern the position of elements on the page when the browser-controlled flow of content just isn’t good enough. To accomplish element positioning, a browser must be able to treat positionable elements as layers[2] that can be dropped anywhere on the page, even overlapping other fixed or positionable elements—something that normal HTML rendering scrupulously avoids.

The notion of layering adds a third dimension to a page, even if a video monitor (or a printed page) is undoubtedly a two-dimensional realm. That third dimension—the layering of elements—is of concern to you as the author of positionable content, but is probably of no concern to the page’s human viewer.

While the CSS-P recommendation offers a cross-platform way to lay out positionable elements, the browsers have extended the idea by turning positionable elements into scriptable objects whose properties can be changed in response to user action. Now you have the opportunity to create some very interactive content: content that flies around the page, hides and shows itself at will, centers itself horizontally and vertically in the currently sized browser window, and even lets itself be dragged around the page by the user.

The implementations of positionable elements in Navigator 4 and Internet Explorer 4 are perhaps the most divergent parts of DHTML to grace both browsers. If you have the luxury of designing an application for only one browser platform, you can focus on the implementation for that browser to the exclusion of the other browser’s idiosyncrasies. Successful cross-platform development, however, requires knowledge of both browsers’ object models (at least as they relate to positionable elements) and the range of DHTML authoring capabilities in both browsers. As you will see in this chapter, there is a common denominator of functionality, but it is often up to you to raise the level of commonality in order to get a highly interactive page to work identically in both browsers.

Creating Positionable Elements

Regardless of browser, you can make any HTML container element (an element with a start and end tag) a positionable element. As a ridiculous example of how true the preceding statement is, you could direct a browser to render a word surrounded by <B>/</B> tags at a position that is 236 pixels below its normal place in a paragraph (but why would you?).

CSS-P Elements

To turn an HTML element into a positionable element that works in both Navigator 4 and Internet Explorer 4, you must assign it a CSS style rule that has a special attribute: position . As demonstrated in Chapter 3, you can assign this style attribute by including a STYLE attribute in the actual HTML tag or using an ID selector for the rule and setting the corresponding ID attribute in the element’s HTML tag.

The following HTML document demonstrates the two techniques you can use to turn an element into a positionable element:

<HTML>
<HEAD>
<STYLE TYPE="text/css">
    #someSpan {position:absolute; left:10; top:30}
</STYLE>
</HEAD>
<BODY>
<DIV ID="someDiv" STYLE="position:absolute; left:100; top:50">
Hello.
<SPAN ID="someSpan">
Hello, again.
</SPAN>
</DIV>
</BODY>
</HTML>

The first technique defines an ID selector inside a <STYLE> tag that is mated to an ID attribute of a SPAN element in the document’s body. The second method defines the style as an inline attribute of a <DIV> tag. As with ordinary CSS style sheets, you can use any combination of methodologies to apply position style rules to elements in a document.

Once you have set the position attribute, you can set other CSS-P attributes, such as left and top, to position the element. Possible values for the position attribute are:

absolute

Element becomes a block element and is positionable relative to the element’s positioning context.

relative

Element maintains its normal position in element geography (unless you override it) and establishes a positioning context for nested items.

static

Item is not positionable and maintains its normal position in element geography (default value) .

Absolute Versus Relative Positioning

The position attribute terminology can be confusing because the coordinate system used to place an element depends on the positioning context of the element, rather than on a universally absolute or relative coordinate system. A positioning context defines a point somewhere on the screen that is coordinate point 0,0. The most basic positioning context is the invisible box created by virtue of the <HTML> tag set of the document, corresponding to the BODY element. In other words, the entire (scrollable, if necessary) space of the browser window or frame that displays the content of the document is the default positioning context. The 0,0 coordinate point for the default positioning context is the upper left corner of the window or frame. You can position an element within this context by setting the position attribute to absolute and assigning values to the left and top attributes of the style rule:

<DIV ID="someDiv" STYLE="position:absolute; left:50; top:100">
Hello. And now it's time to say goodbye.
</DIV>

Figure 4.1 shows how this simple block-level element appears in a browser window.

An element positioned within the default positioning context

Figure 4-1. An element positioned within the default positioning context

Each time an element is positioned, it spawns a new positioning context with the 0,0 position located at the top left corner of that element. Therefore, if we insert a positioned element in the previous example nested within the DIV element that forms the new positioning context, the newly inserted element lives in the new context. In the following example, we insert a SPAN element inside the DIV element. Positioning attributes for the SPAN element place it 10 pixels in from the left and 30 pixels down from the top of its positioning context—the DIV element in this case:

<DIV ID="someDiv" STYLE="position:absolute; left:100; top:50">
Hello. 
<SPAN ID="someSpan" STYLE="position:absolute; left:10; top:30">
Hello, again. 
</SPAN>
And now it's time to say goodbye.
</DIV>

Figure 4.2 shows the results; note how the DIV element’s positioning context governs the SPAN element’s location on the page.

A second element nested inside another

Figure 4-2. A second element nested inside another

Notice in the code listing that the position attribute for each element is absolute, even though you might say that the nested SPAN element is positioned relative to its parent element. Now you see why the terminology gets confusing. The absolute positioning of the SPAN element removes that element from the document’s content flow entirely. The split content of the parent DIV element closes up, as if the content of the SPAN element wasn’t there. But the SPAN element is in the document—in its own plane and shifted into a position within the DIV element’s positioning context. All other parent-child relationships of the DIV and SPAN elements remain intact (style sheet rule inheritance, for instance), but physically on the page, the two elements appear to be disconnected.

The true meaning of relative positioning can be difficult to visualize because experiments with the combination of absolute and relative positioning often yield bewildering results. Whereas an absolute-positioned element adopts the positioning context of its HTML element parent, a relative-positioned element adopts the positioning context of the element’s normal (unpositioned) location within the document’s content flow. A sequence of modifications to some content should help demonstrate these concepts.

To begin, here is a fragment with a single absolute-positioned DIV element that contains three sentences:

<DIV ID="someDiv" STYLE="position:absolute; left:100; top:50">
Hello. 
Hello, again. 
And now it's time to say goodbye.
</DIV>

This code generates a simple line of text on the page, as shown in Figure 4.3.

A simple three-sentence DIV element

Figure 4-3. A simple three-sentence DIV element

Pay special attention to the location of the middle sentence as it flows in normal HTML. Now, if that second sentence is made into a relative-positioned SPAN element supplied with some offset (left and top) values, something quite unusual happens on the screen. The following fragment positions the second sentence 10 pixels in from the left and 30 pixels down from the top of some positioning context:

<DIV ID="someDiv" STYLE="position:absolute; left:100; top:50">
Hello. 
<SPAN ID="someSpan" STYLE="position:relative; left:10; top:30">
Hello, again. 
</SPAN>
And now it's time to say goodbye.
</DIV>

But what is that context? With a relative-positioned element, the anchor point of its positioning context is the top left corner of the place (the box) where the normal flow of the content would go. Therefore, by setting the left and top attributes of a relative-positioned element, as in the previous code fragment, you instruct the browser to offset the content relative to its normal location. You can see the results in Figure 4.4.

The relative-positioned element generates its own positioning context

Figure 4-4. The relative-positioned element generates its own positioning context

Note how the middle sentence is shifted within the context of its normal flow location. The positioning context established by the relative-positioned element is now available for positioning of other elements (most likely as absolute-positioned elements) that you may wish to insert within the <SPAN> tag pair. Take special notice in Figure 4.4 that the browser does not close up the space normally occupied by the SPAN element’s content because it is a relative-positioned element; had it been absolute-positioned, the surrounding text would have closed the gap. All this behavior is dictated by the CSS-P recommendation.

In most cases, you don’t assign values for left and top to a relative-positioned element because you want to use a relative-positioned element to create a positioning context for more deeply nested elements that are absolutely positioned within that context. Using this technique, regular content flows according to the browser window’s current size or as its appearance is affected by style rules, while elements that must be positioned relative to some running content are always positioned properly.

To demonstrate this concept, consider the following fragment that produces a long string of one-word sentences. The goal is to have the final sentence always appear aligned with the final period of the last “Hello” and 20 pixels down. This means that the final sentence needs to be positioned within a context created for the final period of the last “Hello.” In other words, the period character must be defined as a relative-positioned element, so that the nested SPAN element can be positioned absolutely with respect to the period. The following code shows how it’s done:

<DIV ID="someDiv" STYLE="position:absolute; left:100; top:50">Hello. Hello. 
Hello. Hello. Hello. Hello. Hello. Hello. Hello. Hello. Hello. Hello. Hello. 
Hello. Hello. Hello<SPAN ID="someSpan" STYLE="position:relative">.
<SPAN ID="anotherSpan" STYLE="position:absolute; top:20">
And now it's time to say goodbye.
</SPAN>
</SPAN>
</DIV>

Carefully observe the nesting of the elements in the previous example. Figure 4.5 shows the results in a small browser window.

A relative-positioned element creates a positioning context for another element

Figure 4-5. A relative-positioned element creates a positioning context for another element

If you resize the browser window so that the final “Hello” appears on another line or in another vertical position on the page, the final sentence moves so that it always starts 20 pixels and just to the right of the period of the final “Hello” of the content. When applied in this fashion, the term “relative positioning” makes perfect sense.

Overlapping Versus Wrapping Elements

One of the advantages of CSS-Positioning is that you can set an absolute position for any element along both the horizontal and vertical axes as well as its position in stacking order—the third dimension. This makes it possible for more than one element to occupy the same pixel on the page, if you so desire. It is also important to remember that absolute-positioned elements exist independently of the surrounding content of the document. In other words, if a script shifts the position of such an element, the surrounding content does not automatically wrap itself around the new position of the element.

If your design calls for the content of an element to wrap around another element, you should use the CSS float attribute, rather than CSS-Positioning. Properties of the float attribute let you affix an element at the left or right margin of a containing block element and at a specific location within the running content. For example, if you want to place an image in the middle of a paragraph, you wrap that image element inside a SPAN element whose style sets the float attribute, as follows:

<P>Lots of text.
<SPAN STYLE="float:right; width:120">
<IMG SRC="myImg.gif" HEIGHT=90 WIDTH=120>
</SPAN>
And more text.</P>

Now, no matter how the browser window is sized or how the font rendering varies from platform to platform, the text in the paragraph always wraps around the image. A floating element defined in this manner, however, is not a positionable element in that you cannot script positionable element properties of such an item.

Netscape Layers

Netscape Navigator 4 provides an alternate syntax for creating positionable elements in the form of two sets of tags that are not recognized by IE 4 or HTML 4.0. They are the <LAYER> and <ILAYER> tags, which correspond to absolute and relative positioning styles, respectively. The basic concepts of absolute and relative positioning from CSS-P apply to these tags, so the discussion earlier in this chapter about the two positioning styles applies equally well to Netscape layers. Because you use HTML tags to generate these elements, attributes are set like regular HTML attributes (attributeName="value"), rather than with the CSS-style rule syntax (attributeName:value).

The <LAYER> tag generates an element that can be absolute-positioned within the positioning context of the next outer layer (or the base document if that’s the next outer layer). The following code fragment from the body of a document generates the same content shown earlier in Figure 4.2:

<LAYER NAME="someLayer" LEFT=100 TOP=50>
Hello. 
<LAYER NAME="anotherLayer" LEFT=10 TOP=30>
Hello, again. 
</LAYER>
And now it's time to say goodbye.
</LAYER>

The inner layer (anotherLayer) is absolute-positioned relative to the next outer layer (someLayer). That outer layer is absolute-positioned relative to the default positioning context of the document.

In the following fragment, the inner layer is changed to be a relative-positioned element by using the <ILAYER> tag (inline layer):

<LAYER NAME="someLayer" LEFT=100 TOP=50>
Hello. 
<ILAYER NAME="inLineLayer" LEFT=10 TOP=30>
Hello, again. 
</ILAYER>
And now it's time to say goodbye.
</LAYER>

The <ILAYER> tag lets you designate a piece of running content that has its own positioning context. In this case, the <ILAYER> content is positioned within that context, leaving a gap in the running content, as shown earlier in Figure 4.4.

A more practical application of the <ILAYER> tag is to use it to set a positioning context for further nested absolute-positioned layers. Thus, in the following code fragment, an <ILAYER> is applied to the final period of the outer layer. The <LAYER> tag nested inside the <ILAYER> tag obeys the positioning context of that inline layer, such that the final content tracks the location of the period regardless of normal content wrapping, as shown earlier in Figure 4.5:

<LAYER ID="someLayer" LEFT=100 TOP=50>Hello. Hello. Hello. 
Hello. Hello. Hello. Hello. Hello. Hello. Hello. Hello. Hello. Hello. Hello.
Hello. Hello<ILAYER NAME="inLineLayer">.
<LAYER NAME="anotherLayer" TOP=20>
And now it's time to say goodbye.
</LAYER>
</ILAYER>
</LAYER>

There is more to the Netscape layer than its simply being an alternative syntax to CSS-Positioning. Each layer and inline layer object can have external content associated with it (via an SRC attribute, as documented in Chapter 8). In fact, in the document object model for Navigator 4, each layer object contains its own document object, which a script can manipulate like any document object. This object model is vastly different from the one Internet Explorer 4 uses for positionable objects, so when it comes to writing scripts that reference positionable objects, the situation gets a bit gnarly, as described later.

One other point about the relationship between Netscape layers and CSS-P objects is that Navigator automatically converts CSS-P objects into layers for the object model of the currently loaded document. For example, the following document defines one positionable element in CSS-P syntax:

<HTML>
<HEAD>
</HEAD>
<BODY>
<DIV STYLE="position:absolute; left:100; top:50">
Hello.
</DIV>
</BODY>
</HTML>

Navigator 4’s object model treats the DIV element as a layer; “Hello.” is the content of the layer’s document object. Therefore, while Navigator’s scripting environment works only with layer objects for controlling positioning, you have the same level of scriptability whether a positionable element is defined as a Navigator layer or as a CSS-P element.



[2] I use the term “layer” guardedly here. While the word appears in the Netscape DHTML lexicon (Navigator has a <LAYER> tag and a scriptable layer object), you probably won’t see the same word being used by the Microsoft camp. My application of the term is generic and it aptly describes what’s going on here: a positionable element is like an acetate layer of a film cartoon cel. The cartoon artist starts with a base layer for the scene’s backdrop and then positions one or more acetate layers atop the background; each layer is transparent except for some or all of the art for a single frame of the film. For the next frame of the cartoon, perhaps one of the layers for a character in the background must move a fraction of an inch. The artist repositions that layer, while the others stay the same. That’s what I mean by “layer” in this context.

Get Dynamic HTML: The Definitive Reference now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.