Previous: CSS Positioning and Layers Next: Cross-Browser DHTML Example

Dynamic Positioning and Layers

Up until now, we've discussed using CSSP to create divisions of elements that can overlap one another. You saw how you can use the z-index to change the relative position of each layered element, and how individual elements or boxes can be placed at absolute and relative points in the browser window. In this section, we'll look at how to use this knowledge to work with DHTML layers.

First, it's worth noting that layers are more of a concept than a particular set of parameters that you need to learn. In the previous section, you saw layers of elements that could be absolutely positioned. In CSSP, that's really the extent of what a layer is. The term is commonly used, however, when you're specifically using the <div> element to create each layer, and more to the point, when you use scripting to make the positioning of those layers dynamic in some way.

There is a special case where the term layer takes on more significance—when you're dealing with Netscape 4.x, which includes support for a <layer> element. (Netscape 6 also supports it for backward compatibility, but it's not recommended.) Because the <layer> element is obsolete, I'll only touch on it briefly. But you should know it exists, particularly in case you come across some preexisting code for managing layers.

CSSP Layers

When you're creating CSSP-based layers, the only real difference from what you've seen so far in this chapter is a matter of convention rather than a matter of rule. When you're creating a layer, you'll generally use the ID selector (#) in your <style> definitions, instead of a class definition, because each layer you create needs a unique ID. That's accomplished using a combination of the # symbol and, again by convention, the <div id="layer_name"> element.

Listing 7 is an example of two layers defined using the ID selector and the <div> element.

Listing 7 Creating CSSP Layers

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSSP Layers</title>

<style type="text/css">
#mydiv1 {
position:absolute;
top:50px;
left:50px;
height:300px;
width:500px;
}

#mydiv2 {
position:absolute;
top:350px;
left:50px;
height:300px;
width:500px;
}
</style>
</head>

<body>

<!--Begin first layer -->
<div id="mydiv1">

<img src="1980main.jpg" />

<p>This beautiful 3/2 farmhouse is right in the heart of Old Towne, taking you out of 
the suburbs and back to within walking distance of not only the drug store, but the 
drug store's soda fountain! Put life back the way it's supposed to be, at $125,000.</p>


</div>
<!--End first layer -->

<!--Begin second layer -->
<div id="mydiv2">
  
<img src="1730maple.jpg" />

<p>
Not only does this neighborhood have good schools and good shade trees, it's got great 
sidewalks. Get out and meet your new neighbors, or strap on that helmet and get back on 
that bicycle you haven't ridden in years. The bike path in front of this property takes 
you right along Creekside Drive and into the county park! This 2/2 cottage has two 
porches and a two-car garage with studio apartment. Only $135,000.
</p>

</div>
<!--End second layer -->

</body>
</html>

The result is two nice, well-defined <div> elements that can be used to alter the positioning, or even visibility, of the enclosed elements, as you'll see in the next two sections. As a quick example, though, all you would have to do is swap the names of the ID selectors in the style definition:

<style type="text/css">
#mydiv2 {
position:absolute;
top:50px;
left:50px;
height:300px;
width:500px;
}

#mydiv1 {
position:absolute;
top:350px;
left:50px;
height:300px;
width:500px;
}
</style>

If you did that and tested the result in a browser, you'd see that the two layers had switched places, with the second <div> container on top and the first <div> container below it.

Dynamic Positioning

Now that you've seen how to position elements on the page, the next step is to introduce some JavaScript to your pages, thus making them truly dynamic. (Otherwise, it isn't really Dynamic HTML, is it?) As a simple demonstration, you can take a single object, set its positioning, and use a simple JavaScript to change that position dynamically, thus animating the object in the browser window.

Let's try it. Listing 8 shows the script in action. (Note that, as written, this script will only work in Internet Explorer versions 4 and 5. )

Listing 8 Moving an Item on the Page

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<title>Dynamic Animation</title>
<style>
#headblock {
position: absolute;
left: 25px;
top: 100px;
width: 200px;
}
</style>
</head>

<script type="text/javascript">
<!--

function moveHeading(x, y) {
  x = x + "px";
  y = y + "px";
  headblock.style.left = x;
  headblock.style.top = y;
}

// -->
</script>

<body>

<form>
<pre>
Enter x coordinate: <input type="text" id="xcoord" />
Enter y coordinate: <input type="text" id="ycoord" />
<input type="button" value="Click to Submit" onclick="moveHeading(xcoord.value, ycoord.value)">
</pre>
</form>

<div id="headblock">
<h1>Man Bites Cat</h1>
<p><strong>Orwitz, Nevada</strong> -- In a bizarre story that has local officials 
scratching their heads, an Orwitz man has been questioned in an alleged biting attack 
on a feline. Rich Cutter, 42, a noted local physician, apparently scrambled up a tree 
in his backyard in pursuit of the cat, which lives with a neighbor. It was in that tree 
that the alleged biting incident took place.</p>
</div>


</body>
</html>

When you enter values and click the Click to Submit button, the function assigns those values to the appropriate style values. Note that the left and top properties require values that specify the units (in this case, px for pixels), so they need to be added to the value before it's assigned to the properties. Figure 9 shows this.

Figure 9 Enter figures and click the Click to Submit button, and the layer is moved to a new location on the page.

So why doesn't this work in Netscape? Basically, because Netscape references individual objects from the DOM a bit differently from IE. To work in Netscape version 6.0 (as well as IE 5.5 and higher), you would need to change the function slightly:

function moveHeading(x, y) {
  headblock = document.getElementById("headblock");
  x = x + "px";
  y = y + "px";
  headblock.style.left = x;
  headblock.style.top = y;
}

Netscape 6 uses the W3C's DOM approach to storing elements in the document object. This is different from Microsoft's 4-level approach, which is to place each named element in the document object automatically. A hybrid approach would require that you first detect which browser your user has, and then assign the substitute object variable (headblock=) for Netscape. We'll discuss how to do that a little later in this chapter in the section "Cross-Browser DHTML Example. "

NOTE

Just because Netscape 6's approach is different from the IE4-compatible approach doesn't mean Netscape 6 is wrong—it's actually closer to the W3C's standard for the DOM. In fact, Internet Explorer 5.5 supports the getElementById() method as well. But if you want to be compatible with IE4 and up, you need to use the older IE method.

CSSP Visibility

There's one other new property that CSSP brings to the style sheet: visibility. The options are visible, hidden, and the default, auto. By adding the property to your script class definition, you can determine whether or not any elements that have that class will appear in the browser window:

#mydiv1 {
position:absolute;
top:50px;
left:50px;
height:300px;
width:500px;
visibility: hidden;
}

By adding this to the sample script shown in Listing 7, you end up with a page that looks like Figure 10. Suddenly, the story text is gone. (Actually, only the first paragraph is gone, which is the only one that I've given this particular class for the example.)

Figure 10 With the first <div> set to hidden, there's a gap on the page.

Hiding the text and elements you've sweated over in your XHTML authoring probably doesn't seem all that appealing. But the visibility property gets more interesting when you mix in some JavaScript.

Using the two together, you could set up a page somewhat akin to the image-swapping page back in Listing 2, except that you're able to swap an entire layer of content instead of an image. You do this by defining a division of content, giving it an ID, and then assigning a visibility property to that division. In Listing 9, you'll also find that the blocks have been positioned absolutely, and positioned so that they exactly overlap one another.

NOTE

Again, as written, this example only works in Internet Explorer 4.0 up to version 5.5 because of the way it references the object model.

Listing 9 Using Visibility to Swap Content

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Changing Visibility</title>

<style type="text/css">
#mydiv1 {
position:absolute;
top:50px;
left:50px;
height:400px;
width:500px;
visibility:visible;
}

#mydiv2 {
position:absolute;
top:50px;
left:50px;
height:400px;
width:500px;
visibility:hidden;
}
</style>

<script>
<!--
function changeVis () {
  if (mydiv1.style.visibility != "hidden") {
    mydiv1.style.visibility = "hidden";
    mydiv2.style.visibility = "visible";
    }
  else {
    mydiv1.style.visibility = "visible";
    mydiv2.style.visibility = "hidden";
    }
} 
// -->
</script>
</head>

<body>

<form>
<input type="button" value="Click me" onclick="changeVis()">
</form>

<!--Begin first layer -->
<div id="mydiv1">

<img src="1980main.jpg" />

<p>This beautiful 3/2 farmhouse is right in the heart of Old Towne, taking you out 
of the suburbs and back to within walking distance of not only the drug store, but 
the drug store's soda fountain! Put life back the way it's supposed to be, at $125,000.</p>


</div>
<!--End first layer -->

<!--Begin second layer -->
<div id="mydiv2">
  
<img src="1730maple.jpg" />

<p>
Not only does this neighborhood have good schools and good shade trees, it's got 
great sidewalks. Get out and meet your new neighbors, or strap on that helmet and 
get back on that bicycle you haven't ridden in years. The bike path in front of this 
property takes you right along Creekside Drive and into the county park! This 2/2 
cottage has two porches and a two-car garage with studio apartment. Only $135,000.
</p>

</div>
<!--End second layer -->

</body>
</html>

The page creates the two <div> elements and renders the content for both, hiding the second <div> because of its visibility property. When the button is clicked, the script function is invoked. It checks the first <div> element to see if it's currently visible. If it is, that <div> is hidden and the second <div> is made visible. If the first <div> is already hidden, the opposite takes place. The result is that every time the button is clicked, the images and text swap places, as shown in Figure 11.

Figure 11 On the left, the page before clicking the button; on the right, the page after clicking reveals the second <div> element's contents.

Again, this doesn't work in Netscape because of the DOM differences between the two. To make it work in Netscape version 6.0 and IE 5.5 or higher, you would need to change the function slightly:

function changeVis () {
  mydiv1 = document.getElementById("mydiv1").style;
  mydiv2 = document.getElementById("mydiv2").style; 
  if (mydiv1.visibility != "hidden") {
    mydiv1.visibility = "hidden";
    mydiv2.visibility = "visible";
    }
  else {
    mydiv1.visibility = "visible";
    mydiv2.visibility = "hidden";
    }

NOTE

As mentioned, there's more on these issues in the "Cross-Browser DHTML Example" section later in this chapter.

Netscape Layers

In Netscape 4.x browsers, a different approach to layers was taken with the <layer> element. That element never was terribly popular, and more to the point, it wasn't accepted as a standard HTML or XHTML element. In version 6 of its browsers, Netscape has moved to CSSP standards for positioning, although the <layer> element is still around for backward compatibility.

There are a few key differences between the <layer> element and its CSSP counterparts:

Once you've seen the CSSP positioning approach at work, the <layer> approach doesn't seem terribly foreign. Listing 10 is an example.

Listing 10 Using Netscape Layers for Positioning

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Netscape Layers</title>
</head>

<body>

<layer id="mydiv1" top="50" left="50">

<img src="1980main.jpg" />

<p>This beautiful 3/2 farmhouse is right in the heart of Old Towne, taking you out of 
the suburbs and back to within walking distance of not only the drug store, but the drug 
store's soda fountain! Put life back the way it's supposed to be, at $125,000.</p>

</layer>

<layer id="mydiv2" top="500" left="50">
  
<img src="1730maple.jpg" />

<p>
Not only does this neighborhood have good schools and good shade trees, it's got great 
sidewalks. Get out and meet your new neighbors, or strap on that helmet and get back on 
that bicycle you haven't ridden in years. The bike path in front of this property takes you 
right along Creekside Drive and into the county park! This 2/2 cottage has two porches and a 
two-car garage with studio apartment. Only $135,000.
</p>

</layer>

</body>
</html>

Like <div>, the <layer> container surrounds all the text and markup that will be on that layer. Unlike <div>, the style changes are added as attributes to the <layer> element instead of via a style sheet definition. The positioning is absolute in nature—the specified coordinates are relative to the browser window.

You've seen some of the attributes that <layer> can accept, but let's take a closer look at them and some others not yet mentioned. You'll notice that most of them mirror the CSSP property names:

id This attribute gives the layer a unique identifier.
left and top These attributes determine how far from the left and top of the layer's parent element the layer will appear. With the <layer> element, all positioning is similar to absolute positioning in CSSP. Units are assumed to be pixels, so no px is needed.
pagex and pagey These attributes can be used to arrange the layer based on the page's dimensions, even if another parent element is present.(That is, even if the <layer> element is nested in another element.)
src With the <layer> element, you can use the src attribute to specify an outside file for the layer.
width and height Set the dimensions of the layer's box. These attributes assume the dimensions are in pixels, but they can also be a percentage of the page, as in height="50%".
clip With this attribute, you can decide that only a portion of the layer will be visible, using four values that represent the left, top, right, and bottom points of the clipping region. An example would be clip="5,5,100,100".
z-index As with the similar CSSP property, z-index is used to determine where a layer fits above or below other layers. The higher the number, the closer the layer is to the top.
visibility Again similar to the CSSP property, the visibility attribute can accept three values: show, hidden, and inherit. The inherit value is used to set the current layer to the same visibility as its parent.
bgcolor and background The <layer> element can accept a background color setting (using color names or color hexadecimal values). The background attribute accepts the URL to an image to be placed in the background of the layer.

In addition to all these attributes, there is also the <nolayer> container, which displays its contents in browsers that don't recognize the <layer> element. For example:

<nolayer>
This page is only viewable in Netscape 4.0-level browsers or higher.
</nolayer>

Netscape's Inline Layer

Netscape's answer to the relatively positioned CSSP element is the <ilayer> element, which can be used to specify an inline layer. Just as with a relative-positioned CSSP layer, an <ilayer> begins at the place it generally would as the next logical element, but then the top and left attributes can be used to move it from that position.

This code snippet is an example:

<body>
<p>This is a regular XHTML paragraph.</p>
<ilayer id="para2" left="10">
<p>This paragraph began at its natural origin, then moved ten pixels to the right.</p>
</ilayer>
<p>This paragraph is another regular paragraph, back at the "natural" origin.</p>
</body>

Scripting Netscape's Layers

As with CSSP layers, you can use JavaScript or a similar language to manipulate Netscape's layers. The layer object model is slightly different from the CSSP object model (which is also different between browser versions), so it's a little tricky to learn. Fortunately, on its own, accessing Netscape layer properties is pretty easy. They follow this basic structure:

layerName.propertyName

Netscape includes a number of methods for the <layer> element, which are accessed using this familiar structure:

layerName.methodName()

Unlike many objects and elements rendered in Netscape 4, layers can be changed dynamically. You can use them in Netscape 6 as well, although the CSSP properties also allow for dynamic changes and are closer to cross-platform.

The layer object's properties mirror the attributes almost exactly, such as layer1.top, layer1.visibility, and so on. The one major difference is the clip attribute, whose properties are accessed individually at layer1.clipleft, layer1.clipright, layer1.cliptop, and layer1.clipbottom.

The layers themselves are actually held in an array of layers that are part of the document object. To access a particular layer, you can use the name of the layer as the index for the array:

document.layers["layer1"]

In many cases, you'll want to set the layer in question to a new variable that can be accessed as a standalone object:

myLayer = document.layers["layer1"];

The properties and methods of that particular layer can then be accessed using the new layer variable:

myLayer.top = 5;

The layer object also includes a number of methods that don't have corollaries in the CSSP world. These methods are used to directly manipulate layers, making it a little easier to animate them and make them visible or hidden. Table 2 shows many of the methods available for use with layers.

Table 2 Layer Object Methods

Method

Description

moveBy(x,y)

Moves the layer by the number of pixels

moveTo(x,y)

Moves the layer to particular pixel coordinates, relative to the layer's parent

moveToAbsolute(x,y)

Moves the layer to the specified coordinates on the page

resizeBy(width, height)

Grows or shrinks the layer by the number of pixels specified

resizeTo(width, height)

Changes layer size to the exact specified pixel values

moveAbove(layerName)

Places this layer above the specified layer

moveBelow(layerName)

Stacks this layer below the specified layer

load(src, width)

Changes the source of a layer to the contents of a file


In Netscape 4, note that resizing layers doesn't reposition the text and markup like you might think it would. Instead, it acts more like the clip attribute, in that it simply makes more or less of the layer visible. Methods are used in the same way that they are in any JavaScript code:

layer1.resizeTo(250, 500);

Now you're ready to toss in some JavaScript. In this example, the approach is similar to the layer movement shown in Listing 9, where two layers are specified and clicking a button changes their visibility. Listing 11 shows the scripting of <layer> elements.

Listing 11 Changing a Layer's Visibility

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Netscape Layers</title>
<script>
<!--

function changeLayer () {
  window.alert(document.mydiv1.visibility);
  if (document.mydiv1.visibility != "hide") {
    document.mydiv1.visibility = "hide";
    document.mydiv2.visibility = "show";
    }
  else {
    document.mydiv1.visibility = "show";
    document.mydiv2.visibility = "hide";
    }
} 
// -->
</script>

</head>

<body>

<form>
<input type="button" value="Click me" OnClick="changeLayer()">
</form>

<layer id="mydiv1" top="50" left="50">

<img src="1980main.jpg" />

<p>This beautiful 3/2 farmhouse is right in the heart of Old Towne, taking you out of the 
suburbs and back to within walking distance of not only the drug store, but the drug store's 
soda fountain! Put life back the way it's supposed to be, at $125,000.</p>


</layer>

<layer id="mydiv2" top="50" left="50" visibility="hide">
  
<img src="1730maple.jpg" />

<p>
Not only does this neighborhood have good schools and good shade trees, it's got great 
sidewalks. Get out and meet your new neighbors, or strap on that helmet and get back on 
that bicycle you haven't ridden in years. The bike path in front of this property takes 
you right along Creekside Drive and into the county park! This 2/2 cottage has two porches 
and a two-car garage with studio apartment. Only $135,000.
</p>

</layer>

</body>
</html>

You can see that this script is very similar to the script used for CSSP, with the exception of the <layer> elements and the object model used to access those items. In fact, you can pare that down even more, as you'll see in the next section.

Previous: CSS Positioning and Layers Next: Cross-Browser DHTML Example