Working With Frames
Since Netscape Navigator 2 and Internet Explorer 3, developers have had the ability to include frames in their web pages. Frames represent a step forward in Web Development in that they give the developer the ability to display information on the screen in a more robust manner. Frames are really nothing more than individual windows within another window. When you name your frames, you gain the ability to target a specific frame (location) for your information. The result is that you can "anchor" parts of the information on your page and change the content of other parts with minimal effort.
Frames, however, are not without their downside. In most cases, when you use frames, you are asking the browser to download more than a single page and place each page within its own frame. The simple fact is that downloading a frames-based page takes longer than downloading a non-frames page. Another mark against frames-based pages is that they wreak havoc on a user's Back button. When the Back button of the browser is used, the user is not sent back to the previous page unless they are viewing the first document in the frameset. Rather, they are sent to the previous frame. This can lend confusion to the user's experience.
Creating Frameset Documents
When you want to use frames, you must create a frame definition document that describes the structure of all the frames you will create. This document is the one that will "fill" each individual frame with its own content, size and position frames, and name the frames. In general, you create a frameset by declaring how many rows or columns it contains and what size each should be. Then, you fill the contents of each frame with an HTML document. As you'll soon see, when you create a frame definition document, you will not use a <body> element. Instead, you will use the <frameset> element. In fact, you can consider the <body> and <frameset> elements as mutually exclusive. You really can't use one with the other.
When you use the <frameset> element, you must specify whether your frames will be rows or columns. You do this by using either the rows attribute or the cols attribute. Once again, these attributes are mutually exclusive. You cannot use both rows and cols to define a <frameset>. You can, however, nest <frameset> elements inside other <frameset> elements. But that's a topic for a little later! Let's do a simple example and then analyze the code:
<html>
<head>
<title>Simple Frames 1</title>
</head>
<frameset rows="100,50%,*">
<frame name="row1" src="row.htm">
<frame name="row2" src="row2.htm">
<frame name="row3" src="row3.htm">
</frameset>
</html>
The very first thing to notice is that there is no <body> element. Again, when you create framesets, you don't use the <body> element. But, as you can see, each frame contains an HTML page which will contain a <body> element. Cool! OK, our frameset begins with the <frameset> element. In this example, we are creating a frameset that consists of three rows. The first row will be 100 pixels tall, the second will be 50% of the container of the frameset (in this case, the window) and the third will consume the rest of the space on the screen. You can see that there are three ways to specify the width or height of rows and columns: you can use a number to denote pixels, a percent for relative widths, and the * (wildcard) to "soak up" the rest of the screen.
Once we have determined that our frameset will contain three rows, we must then include three <frame> elements - one for each frame. Each <frame> element takes a src attribute which points to the location of the page to load in the frame. Although naming your frames isn't required, get used to doing so. This will allow you to target individual frames inside your frameset. Notice, also, that the <frame> element is empty - like the <img> element. The convention is to not close the <frame> element - something new for us! For now, we will leave the <frame> element unclosed for simplicity's sake. So here is what our frameset might look like (note - these diagrams are actually done using tables):
|
|
|
Let's try another example that uses columns:
<html>
<head>
<title>Simple Frames 2</title>
</head>
<frameset cols="100,*">
<frame name="col1" src="col.htm">
<frame name="col2" src="col2.htm">
</frameset>
</html>
And here is what that one might look like:
|
|
So far so good! Creating framesets isn't really all that difficult, is it? Let's explore the possible attributes of the <frameset> element:
Attribute |
Description |
---|---|
frameborder |
Allows you to turn off the border around a frameset. A value of 1 draws the borders, while a value of 0 creates borderless frames. For the borders to not be drawn, all the frames sharing a common border must have their frameborder attribute set to "0". |
border |
Allows you to specify the width of the borders in the frameset (Netscape only). |
bordercolor |
Allows the user to set the color of the frame borders in a frameset, specified in an RGB triplet (Netscape only). |
Now let's explore the attributes for the <frame> element:
Attribute |
Description |
---|---|
frameborder |
Allows you to turn off the border around a frame. A value of 1 draws the borders, while a value of 0 creates borderless frames. For the borders to not be drawn, all the frames sharing a common border must have their frameborder attribute set to "0". |
framespacing |
Determines the space around (between) a given frame in pixels (IE only). |
marginheight |
Sets the top and bottom margins of the frame equal to the value specified in pixels. |
marginwidth |
Sets the left and right margins of the frame equal to the value specified in pixels. |
name |
Assigns a name to the frame for targeting. |
noresize |
Locks the size of the frame. By default, users can resize frames within the browser |
scrolling |
Determines if scrollbars will be displayed for the frame. A value of "auto" specifies that scrollbars will be displayed if necessary (default). A value of "no" specifies that no scrollbars will be drawn. A value of "yes" specifies that scrollbars will be drawn whether they are needed or not. |
src |
Specifies the URL of the document to be loaded into the frame. |
Creating Complex Framesets
So far, we've explored creating the most basic frames pages. In normal use, however, these basic framesets are usually not sufficient to achieve the layout you need. We'll need to explore creating more complex layouts in detail.
As a quick overview before getting to the code, we've created some framesets by using the <frameset> element, specifying how many rows or columns are contained in the frameset, and then populating the <frameset> element with the appropriate number of <frame> elements. What we are about to discover is that we can replace any of the <frame> elements we've created with a second <frameset> element. This process is called "nesting" framesets and it allows us to create very complex layouts. Inside our second <frameset> element, we can specify any number of rows or columns and then populate it in the same fashion. There is no limit to the number of frames you can display on a page. A word of caution, however: a good rule of thumb is to set a maximum number of frames equal to 4. More frames generally confuses users.
OK, let's see if we can modify the columns example into something more useful. Here is what our finished product should look like followed by the code:
|
|
|
And here's the code:
<html>
<head>
<title>Simple Frames 3</title>
</head>
<frameset cols="100,*">
<frame name="toc" src="toc.htm">
<frameset rows="50,*">
<frame name="head" src="head.htm">
<frame name="content" src="content.htm">
</frameset>
</frameset>
</html>
Let's take it one line at a time starting with the first <frameset> element. Here we determine that our frameset will contain two columns. The first will be 100 pixels wide and the second will absorb the rest of the screen width. Next, we create the left frame just as we did in the example above - by using the <frame> element. On the next line is where we would put the second <frame> element but, in this case, we have replaced the second frame with another <frameset> element that specifies two rows. The first row is 50 pixels tall and the second will absorb the rest of the height. We then populate the second frameset with two frames as normal. Then we close the second frameset and finally close the first frameset. Whew! The layout achieved is nearly identical to that of the Just In Time Software page.
Suppose, for a moment, though, that you wanted the "head" frame to stretch all the way across the top of the frameset and the split the row underneath into columns like this:
|
|
|
|
No problem! Just adjust your code so that you declare rows in the first <frameset> element and columns in the second <frameset> element:
<html>
<head>
<title>Simple Frames 4</title>
</head>
<frameset rows="50,*">
<frame name="head" src="head.htm">
<frameset cols="100,*">
<frame name="toc" src="toc.htm">
<frame name="content" src="content.htm">
</frameset>
</frameset>
</html>
A More Useful Example
Let's see if we can modify the Just In Time Software page so that it uses frames for layout instead of tables. Along the way we'll explore targeting, the <base> element, and creating seamless borders within a frameset.
To begin, one of the things we haven't mentioned is the fact that each of our frames must have a src attribute that points to a valid HTML file. This means that we'll need to create the HTML documents for each individual frame beforehand. It looks like we'll need three documents to start: a header to hold our logos, a table of contents to hold our navigation structure, and a content placeholder. We'll use the Simple Frames 3 example for our structure:
<html>
<head>
<title>Just In Time Software</title>
</head>
<frameset cols="125,*">
<frame name="nav" src="nav.htm">
<frameset rows="125,*">
<frame name="head" src="head.htm">
<frame name="content" src="content.htm">
</frameset>
</frameset>
</html>
Now we'll need to create the three pages specified for the three pages we just declared. Here is the code for the nav.htm file:
<html>
<head>
<title>Navigation</title>
<style>
body{
color: rgb(240,240,240);
font-family: Arial, sans-serif;
font-size: 0.8em;
background-color: rgb(00,66,00);
}
a:link{
text-decoration: none;
color: rgb(175,175,50);
}
a:visited{
text-decoration: none;
color: rgb(110,110,33);
}
a:active{
text-decoration: underline;
color: rgb(220,220,66);
}
a:hover{
text-decoration: underline;
color: rgb(220,220,66);
background-color: rgb(110,110,33);
}
</style>
<base target="content">
</head>
<body>
<img border="0" src="images/jitdisc.gif" width="100" height="83">
<p>About Us<br>
<a href="story.htm">Our Story</a><br>
<a href="mission.htm">Our Mission</a><br>
<a href="vision.htm">Our Vision</a>
<p>Services<br>
<a href="webdesign.htm">
Web Design</a><br>
<a href="programming.htm">
Programming</a><br>
<a href="consulting.htm">
Consulting</a><br>
<a href="training.htm">
Training</a><br>
<a href="hosting.htm">
Web Hosting</a></p>
<p>Policies<br>
<a href="privacy.htm">
Privacy Policy</a><br>
<a href="guarantees.htm">
Guarantees</a><br>
<a href="terms.htm">
Terms & Conditions</a><br>
<a href="use.htm">
Acceptable Use</a>
</p>
<p>Contact Us<br>
<a href="custsupport.htm">Customer Support</a><br>
<a href="techsupport.htm">Tech Support</a><br>
<a href="sales.htm">Sales</a><br>
<a href="resellers.htm">Resellers</a><br>
</p>
</body>
</html>
Notice the <base> element and it's accompanying target attribute. We've already learned how to target a new window with a hyperlink. We also learned (but didn't practice!) that we could target any named frame using the same target attribute for each hyperlink. In this example, that would become tedious given that there are so many hyperlinks. So, rather than specify a target for each hyperlink, it would make sense to set a target for the entire page. And that's exactly what the <base> element does: it allows you to specify a target for each hyperlink on a given page. (The <base> element also has an href attribute that allows you to specify a base URL so that the page can be viewed out of context but that's a subject for another time>). The result is that whenever you click on a hyperlink in our nav page, the contents of the link will be loaded into the content frame. Cool!
Here is the code for the head.htm file:
<html>
<head>
<title>Head</title>
</head>
<body>
<p align="center"><img border="0" src="images/jit.gif" width="400" height="100"></p>
</body>
</html>
That one's easy! All we need is the logo in our top frame. Here is the code for our content holder:
<html>
<head>
<title>Head</title>
<style>
body{
color: rgb(33,99,33);
font-family: Arial, sans-serif;
}
a:link{
text-decoration: none;
color: rgb(175,175,50);
}
a:visited{
text-decoration: none;
color: rgb(110,110,33);
}
a:active{
text-decoration: underline;
color: rgb(220,220,66);
}
a:hover{
text-decoration: underline;
color: rgb(220,220,66);
background-color: rgb(110,110,33);
}
</style>
</head>
<body>
So, you're looking for someone to sort out your computer mess - well you've come to the right place. We're Just In Time Software and we do it all better than anyone else. And we get it done Just In Time!
</body>
</html>
OK, we've got all of the pages necessary for our frame definition document in place. Let's see how it looks:
That's a pretty good start but there are a number of problems with the page. First, users can resize all of the frames distorting our layout. Since we are using frames to handle the layout, we should make every effort to guarantee our layout by not letting the user resize our frames. Second, the scrollbar that is visible in the header is just plain ugly! We should make that disappear for purely aesthetic reasons. Finally, the borders around the frames are a nuisance all to themselves. We should try to eliminate the borders and create a seamless page - so the user has no real visible cues that the frames exist. So.... change your frame definition document so that the code looks like this:
<html>
<head>
<title>Just In Time Software</title>
</head>
<frameset cols="125,*" frameborder="0" border="0" framespacing="0">
<frame name="nav" src="nav.htm" noresize>
<frameset rows="125,* frameborder="0" border="0" framespacing="0">
<frame name="head" src="head.htm" scrolling="no" noresize>
<frame name="content" src="content.htm" noresize>
</frameset>
</frameset>
</html>
Now, let's see what it looks like:
Much better! In fact, our frames-based page might actually look better than our table-based page. The frames-based page doesn't have the white border around the navigation features nor does it require blank lines to extend the colored bar. Finally, although we created four separate documents to achieve the effect, the total amount of code necessary to generate the frames-based page is less than the table-based page. We only have the three simple documents that make up our content and the frame definition document. We didn't have to worry about all of the table tags associated with the other page. You can view the Just In Time Software frames based page from the source code page.
So we now know how to do framed web pages. With frames come a lot of power in terms of layouts. But with that power comes a lot of responsibility. You'll need to test your pages more thoroughly - especially in terms of screen resolution to make sure that the end result is what you are looking for at a variety of resolutions. Don't make the mistake of designing a page that looks good on your high-resolution 19 inch monitor but that is awful on the typical 15 inch monitor set to 800 by 600.