I chose to leave the topic of nesting layers until now because they will effect your scripts in a number of places.
Nesting refers to when you want to group several layers together into one uniform element. In other words, nested layers are "layers within layers".
When you do this the child layers will be positioned with respect to their parent layer. Also, if the parent layer is clipped the child layers will appear as if in a window or like a plugin. If the child layers go outside the boundaries (the clip edges) of the parent layer they will become invisible - their visibility property will not change but they will appear as if they are offscreen:
I've found nesting comes in handy when you get into more complicated positioning. Since all the locations of the child layers are with respect to the parent layer, they are permanently "locked" into position. If you later want to move the location of the parent layer, you don't have to change the locations of the child layers because they will move accordingly. This is also true in sliding animations - all the child layers will slide in unison.
The JavaScript for nested layers differs quite dramatically between Netscape and Internet Explorer. I'll admit it is a bit of pain to make scripts with nested layers to work properly in both browsers - and that is the reason you don't see nesting used that often on the web. However I've developed some really great techniques to get around these problems so bear with me here as I assure you that nesting is so useful that once you start using it, you'll want to do just about everything that way.
Stylesheets and Nesting:
To nest layers all you do is wrap the parent DIV around all the child DIV's:
<DIV ID="parent1Div"> <DIV ID="child1Div"></DIV> <DIV ID="child2Div"></DIV> </DIV>
I have noticably left out the styles for these DIV tags. This is because Netscape does not let you nest layers if the styles have been defined using the "inline" method like I have been using for this tutorial up until now. Netscape seems to only allow one set of nested layers, if you use any more then it will totally ignore all the styles for all the layers after it. So right off the bat we're going to ALWAYS define the styles using the STYLE tag. All the examples from this point forward will be done this way.
The CSS is basically the same except it's separated from the DIV tags:
<STYLE TYPE="text/css"> <!-- #parent1Div {position:absolute; left:100; top:80; width:230; height:120; clip:rect(0,230,120,0); background-color:#C0C0C0; layer-background-color:#C0C0C0;} #child1Div {position:absolute; left:-20; top:40; width:70; height:70; clip:rect(0,70,70,0); background-color:#FF0000; layer-background-color:#FF0000;} #child2Div {position:absolute; left:180; top:70; width:70; height:70; clip:rect(0,70,70,0); background-color:#0000FF; layer-background-color:#0000FF;} --> </STYLE> <DIV ID="parent1Div"> <DIV ID="child1Div"></DIV> <DIV ID="child2Div"></DIV> </DIV>
Example: nesting1.html
I also included the clip regions to define the squares. In most cases where you use nesting you usually have to define the clip values and color the layers.
JavaScript and Nesting:
Nesting is where the JavaScript for Netscape and Internet Explorer go in completely opposite directions. In IE, there's no difference whether a layer is nested or not, you access the properties of the layer in the same manner as before:
childLayer.style.properyName
However in Netscape when you want to access the properties of a nested layer (a child layer) you have to reference it with respect to it's parent layer:
document.parentLayer.document.childLayer.propertyName
The extra "document" before the layer names are due to the fact Netscape treates layers as separate documents - a child layer is part of the document of it's parent layer.
It is possible to nest layers an unlimited number of times as well - you just keep wrapping the DIV's over and over again. Say we changed that example set so that child2Div is inside child1Div
<DIV ID="parent1Div"> <DIV ID="child1Div"> <DIV ID="child2Div"></DIV> </DIV> </DIV>
In that case to access the properties of child2Div you'd have to write:
document.parent1Div.document.child1Div.document.child2Div.propertyName
This concept will have to be incorporated into our pointer variables. Here's the way I'd define the pointer variables for that original example set:
function init() { if (ns4) { parent1 = document.parent1Div child1 = document.parent1Div.document.child1Div child2 = document.parent1Div.document.child2Div } if (ie4) { parent1 = parent1Div.style child1 = child1Div.style child2 = child2Div.style } }
Now onto some more problems...
CSS Properties Revisited:
Unfortunately Internet Explorer has a little technicality that poses quite a dilemma that had me baffled for quite a while. When you define the styles for your layers using the STYLE tag, IE does not let you read any the properties initially. So in IE if you were to check the current location of parent1 using:
alert(parent1.left)
You will find that you don't receive any value. This is true for all the CSS properties (left, top, width, height, visibility etc.).
Example: nesting2.html - checks the properties of the layers. In Netscape everything works fine but in IE the alerts will show absolutely nothing.
I am still unclear why Microsoft made IE this way. It only occurs when you use the STYLE tag, and only effects the initial values of properties. Once you start changing the properties in JavaScript you can then access them without problems.
How does this affect our situation? Well, if we want to assign other properties as we did earlier (xpos and ypos) we need a way to find the current location of the layer in some different way for IE4. It's fortunate that Microsoft included some extra non-standard CSS properties into IE4:
These extra properties are not effected by the IE4 STYLE tag problem so we can use those to obtain the current location of the layer. So here's our new code to add our xpos and ypos properties onto our pointer variables:
function init() { if (ns4) { parent1 = document.parent1Div parent1.xpos = parent1.left parent1.ypos = parent1.top child1 = document.parent1Div.document.child1Div child1.xpos = child1.left child1.ypos = child1.top child2 = document.parent1Div.document.child2Div child2.xpos = child2.left child2.ypos = child2.top } if (ie4) { parent1 = parent1Div.style parent1.xpos = parent1.offsetX parent1.ypos = parent1.offsetY child1 = child1Div.style child1.xpos = child1.offsetX child1.ypos = child1.offsetY child2 = child2Div.style child2.xpos = child2.offsetX child2.ypos = child2.offsetY } }
Click here to view this example.
Once you've done that you can change the locations of the layers as before.
Click here to view an example using this function to move the parent and child layers.
Visibility and Nesting:
Again, if you use the STYLE tag to define your layers you will not be able to obtain the original visibility value in IE4. But in my experience, obtaining the visibility is very rarely necessary. Usually you already know if a layer is visible or not. And remember that only effects the initial visibility - after you change the visibility in JavaScript you will then be able to find the value.
Showing and hiding nested layers works pretty much the way you'd expect. Once you've defined the pointer variables you can use the same show/hide functions that I explained in the Showing and Hiding lesson.
But there is one thing that I should point out. If you don't define the visibility for the child layers, their visibility is "inherited" - it takes on the value of the parent layer's visibility. In that case when if you then hide or show the parent layer, all the child layers do the same. BUT... in Netscape if you either define the visibility for the child layers, or you start changing the visibility in JavaScript you lose the ability to hide or show all the child layers at once. In that case when you hide the parent layer, any child layer that is visible will still show through.
To avoid this situation, you have to set the visibility back to "inherit" instead of "visible" ("show" for Netscape). So instead of using the showObj() function, you have to manually set the visibility property:
mychild.visibility = "inherit"
Putting it back to inherit means if the parent is shown, the child layer will also be shown, and if the parent is hidden, it will also be hidden.
Home | Next Lesson: Changing Images (Rollovers) |