=========================================================================== Today on The World Vol. 4 #170 Wednesday, July 1, 1998 =========================================================================== Only two more installments of the HTML tutorial left -- this one (frames) and then the wrap-up installment. Now's your chance to ask questions or request clarification of anything -- please post to wstd.html if you have a question you would like me to consider for the final chapter. Remember that you can find the other chapters on http://world.std.com/help/web/tutorial for now. (kibo) --------------------------------------------------------------------------- HTML TUTORIAL -- CHAPTER 15 -- FRAMES 15.1 Frames -- the rationale Frames, invented by Netscape Inc. and now supported by the major browsers (Netscape Navigator, Microsoft Internet Explorer, even lynx and WebTV) are a way of dividing a web page up into sections, much like tables. The difference is that with frames, each section is a separate .html file -- each frame is effectively an independent page. A table is a single document containing all the cells (and certain tags should not be used inside the cells) whereas within frames, "anything goes". One of the best features of frames is that they can scroll independently. For instance, you could have two frames, one of which contains a small navigation bar (set of links) and doesn't scroll, while the rest of the window is a large scrolling area for the site's text. Frames can be hard to navigate in some browsers (many browsers do odd things when "Back" button is pressed while you're at a framed site, and it can be hard to bookmark a particular location within a framed site) and some people get confused by framed sites. Because of this, some people will disable frames support in their Web browser (usually this can be turned off in "Preferences" or "Options") and some Web designers do not design with frames. (There used to be a "Campaign Against Frames" site discouraging people from using frames, but it seems to have disappeared. Maybe the Netscape Mafia rubbed 'em out.) Frames are a powerful tool when used correctly, however, they can also make your site appear unnecessarily complicated if you use them without good reason. More importantly, if you don't use them correctly, you can easily create a malfunctioning site. 15.2 How frames work -- general structure Every Web site that uses frames requires at least three documents: First, the "frameset" document which describes the relationship of the different panes (but contains no actual content), and second, two or more regular .html files which are displayed in the panes. (I suppose you could make a framed site with only two documents if you only had one pane, but that would be pointless.) The frameset document -- which would normally be index.html so that it gets loaded as the first page people see when they come to your site -- differs from a normal .html file in that it has no ... section. Here's the skeleton of a framed index.html: Framed Site <!-- ...non-frame version of your index... --> Essentially, ... is replaced by ..., which contains only tags specifying what the individual frames (panes) are in the main window. ( tags are like or
in that they have no corresponding end tags.) After that is ..., which is where you would put the non-framed version of the same page. If you've already designed a site without frames, you can take its section and use that as the section. The <NOFRAMES> area is visible in browsers that don't "do" frames (or in when your visitor has chosen to disable frames) so you should have something there which contains links to the frame pages. In other words, <FRAMESET>'s <FRAME> tags point to a group of .html files which are displayed in the panes. <NOFRAMES> is the backup plan, a regular piece of HTML (what would normally be your <BODY>) which allows people to get to the same content if they can't see the frames. (You see, because <FRAMESET> contains only <FRAME> tags, a browser which is too old to know about frames will not know <FRAMESET> or <FRAME> and will ignore all those tags, but it will recognize the stuff in <NOFRAMES>. A browser which knows about frames will process the <FRAME> tags and then recognize <NOFRAMES> as a redundant section which can be skipped.) 15.3 Example of a framed site Now let's look at an example of a working framed site. First we'll make two pages that will be in frames, named navbar.html and content.html: <HTML> <!-- save this as navbar.html --> <HEAD> <TITLE>Navigation bar</TITLE> </HEAD> <BODY BGCOLOR="#660000" TEXT="#FF6666"> <H2 ALIGN="CENTER">...Navigation controls would go here...</H2> </BODY> </HTML> <HTML> <!-- save this as content.html --> <HEAD> <TITLE>Large block of interesting content</TITLE> </HEAD> <BODY BGCOLOR="#CCCCFF" TEXT="#000000"> <BLOCKQUOTE><BLOCKQUOTE> <H1>This document contains the most important text in the universe: The speech Abraham Lincoln gave when he drove the Golden Spike which created the Information Super Railroad, forerunner of the Internet.</H1> <P><BIG>Now is the time for all men to come to the aid in their party. When in the course of human events it is necessary to hold a party, such as our forefathers brought forth, we shall type nonsense text to fill up a frame with liberty and justice for all.</BIG><P> <!-- serious filler here: --> <BR><HR><BR><HR><BR><HR><BR><HR><BR><HR><BR> <P>I hope I've wasted enough space to make this thing scroll.</P> <BR><HR><BR><HR><BR><HR><BR><HR><BR><HR><BR> <P>That's all, folks!</P> </BLOCKQUOTE></BLOCKQUOTE> </BODY> </HTML> Try viewing each of those files. Each one is a complete Web page with <HEAD>, <TITLE>, <BODY>, etc. The second one has a lot of junk in it and looks awful, but that's because I needed to ensure it would scroll up and down so you can see how frames work. Anyway, you now have two working pages which will be the contents of two frames. Now let's create another file named index.html for our frameset document: <HTML> <!-- save as index.html --> <HEAD> <TITLE>Framed Site</TITLE> </HEAD> <FRAMESET ROWS="60, *"> <FRAME SRC="navbar.html" NAME="navbar-frame"> <FRAME SRC="content.html" NAME="content-frame"> </FRAMESET> <NOFRAMES> <H1>Frameless version of my site</H1> <P>If your browser were showing frames, this site would look different.</P> <P>Read my <A HREF="content.html">blue page</A>.</P> Try viewing index.html now and see if it shows two frames. (It should show the dark red navbar.html at the top and the sky blue content.html at the bottom.) Try scrolling the scroll bar. (Hopefully the blue frame has one because I made its content really long. If you don't have a scroll bar, make the window smaller or make your browser's font bigger.) Notice that you can scroll one frame independently of the other. What happens when you make the window wider or narrower, taller or shorter? How do you think that tag explains that we want one small frame of fixed size and one large frame which uses up the rest of the window? Remember how with tables we could specify height and width of a cell () as a percentage of the available space or as a number of pixels? Here we've specified that our frameset will be made of rows (ROWS=, we could also have done COLS=) and the first row (that is, the topmost frame) is exactly 60 pixels tall. We could also have used 10% to make it 10% the size of the window. The other frame gets an asterisk, which, in , means "let the browser pick a good size." In other words, if there's one * in , that frame uses up whatever leftover space there is. If there are two *'s, those two frames may come out equal or unequal depending on which has more stuff in it. More examples: -- two skinny frames at top and bottom, all the leftover space is a big frame in the middle -- two side-by-side frames, diving the window in half -- two side-by-side frames which fill the window, in whatever size the browser thinks is best (depending on content) I recommend using * for any frame that has a lot of content, because you never know how large somebody's browser window or default font will be. If you know exactly how large something is (for instance, suppose your navigation bar is made up of GIFs which are all 24 pixels tall) you would use a frame of a fixed size. But whatever you do, be sure to test your design in a bunch of different browsers on different computers and resize the window a lot to see what happens. The reason the bottom frame scrolls and the top one doesn't (probably, depending on window size) is that we didn't specify whether or not the frames should have scroll bars, so the browser automatically shows them if the content won't all fit on the screen at once. (If you make the window much narrower you may see the top frame display a scroll bar as well.) Change index.html's tags to: Now what happens? Try resizing the window a few times. We've just specified that the small frame should always have a scroll bar and the big frame should never have a scroll bar. So it's probably difficult, if not impossible, to see all the text in the big frame. So maybe you should change those SCROLLING= options to "NO" and "YES". (The default value is "AUTO" which, as you've seen, lets the browser figure out which frames need scroll bars, and it usually works well enough that you don't need to specify SCROLLING="NO" or "YES".) Notice that if we give the top frame the SCROLLING="NO" option and then you make your browser window narrow, you can't see all of the text in the top frame, and you can't scroll it down. But frames are also resizable (by default) as a safety measure (because there are frames where a little text goes off the bottom on lot of badly-designed pages where they don't realize that text will have different font sizes and line lengths in different people's browsers). Position your mouse pointer directly over the bar between the two frames (the cursor may change shape from an arrow to something else when you find the right spot) and drag. You should be able to make the top frame taller or shorter. If you really wanted to prevent your visitors from ever enlarging a frame in case you miscalculate the size of your navigation bar, you could change those tags to: Now the boundary between frames can't be moved. Fortunately, they still scroll because we didn't specify any SCROLLING= option (so we get "AUTO".) Why is the following a very bad idea? In general, I suggest you do not use NORESIZE (it doesn't gain you anything except hiding those little dots some browsers display to show whether or not frames can be resized.) You may have seen some pages that do not draw borders between the frames. Let's change our tags again: That eliminates the thick separator between the frames (although some browsers will still draw a small gap.) You could combine this with the other options, of course. Another fun option, especially combined with FRAMEBORDER="0" is MARGINWIDTH (or MARGINHEIGHT), which is much like CELLPADDING in a table: The margin sizes are specified by the W3C as "must be greater than one pixel", so in other words you can't make frames join together seamlessly, ever. Also, the browsers I've tried usually don't do anything when you specify MARGINWIDTH or MARGINHEIGHT. If you really need to join two images together seamlessly, use instead of frames. 15.4 Links within frames So far the example pages we've been working with don't do anything -- there are no links on them. Here's where it gets tricky and many sites malfunction because their designers don't understand frames: We're going to make links within our frames... then we're going to make links that leave our frames to go to another site. Make a second content page named content2.html: More Content (Part 2)

It's not easy being green, as Kermit the Frog would say. Hey, does he really need "the Frog" in his name? Isn't it a little obvious?

Blather blather blather blather blather. Blither blather, blizzum blazzum. Blather!












I hope I've wasted enough space to make this thing scroll.












That's all, folks!

That's a page that looks much like the baby blue one, except I changed the background color (can you figure out what color it is before previewing it?) and the nonsense filler is different. Great! We've got two pages of content. This means that we can put links in navbar.html to make it do something! Replace everything in navbar.html with this: Navigation bar, Version 2

Do you prefer Blue or Green?

View navbar.html (by itself, not index.html) and you should see a black page with two links. Try following the links. They should take you to the blue and green pages. Now view index.html, which is still set up to have navbar.html at the top and content.html (the blue page) at the bottom. What happens when you follow the links now? Whoops. What's going on? Those links () do not specify which frame the link should be loaded into, so they load into the frame which contains the link by default. That's why when you follow the links in navbar.html the blue or green page appears in the frame that's supposed to contain navbar.html. Let's fix that. Change the links in navbar.html to:

Do you prefer Blue or Green?

Hooray! Now when you follow those links, the bottom half of the window should change to the blue page or the green page without disturbing the navigation bar. How does this work? Notice that we specified TARGET="name of a frame" for each link. Where do those names come from? Open index.html in your text editor and take a look. In fact, while you have index.html open in your editor, there's something else you need to remember to do: The section needs another link so that people who can't see frames can still get to content2.html. I'll let you add that on your own. Going back to navbar.html, the concept of targeting a particular window for your links is very, very, very important. Suppose you wanted to link to another site from navbar.html: <P ALIGN="CENTER"> Do you prefer <A HREF="content.html" TARGET="content-frame">Blue</A>, <A HREF="content2.html" TARGET="content-frame">Green</A>, or <A HREF="http://www.yahoo.com">Yahoo!</A>? </P> That works just fine if you view navbar.html by itself (as a normal, non-framed page), right? But what happens if you view index.html and then click the "Yahoo!" link in the top frame? Congratulations, you've just created a "para-site". That's any framed Web site that doesn't give its links targets so that other people's sites appear within your frames. (This can lead to evil, of course, because then you could pretend that Yahoo! is part of your site...) But how do we fix it? This wouldn't be much better: <P ALIGN="CENTER"> Do you prefer <A HREF="content.html" TARGET="content-frame">Blue</A>, <A HREF="content2.html" TARGET="content-frame">Green</A>, or <A HREF="http://www.yahoo.com" TARGET="content-frame">Yahoo!</A>? </P> That puts it in the bottom frame instead of the top one. The proper way to do this would be to use the special TARGET="_top" name. "_top" is the name of the whole window. Try changing that link to TARGET="_top" and see what happens. It should now do what we want, allowing Yahoo!'s menu to fill the whole window. Now try changing "_top" to "_blank" and see what you get. "_top" loads the link into the whole window; "_blank" loads the link into a new window. (Note that the special names for special parts of windows begin with underscores to keep you from discovering them accidentally when you name your own frames.) So, when linking to someone else's site from within your framed site, you should use TARGET="_top" or "_blank". REPEAT, WHEN LINKING TO SOMEONE ELSE'S SITE FROM WITHIN A FRAME, USE TARGET="_top" OR TARGET="_blank" OR YOU'LL CREATE A PARA-SITE. Notice that if you load navbar.html by itself now, without frames, the links all still work, even the ones that say TARGET="content_frame"; however, since there is no pane named "content_frame", the links open in a new window as if they had specified TARGET="_blank". So you can put TARGET= in all your framed links, and still use the same .html pages with your <NOFRAMES> version. (You could add navbar.html to the <NOFRAMES> part of index.html if you want to.) You can also use TARGET= for other things that work like links, including <AREA> within imagemaps (see Chapter 13 for brief notes on imagemaps) or <FORM> (in case you want the results of the form to be displayed in a particular frame or "_top".) The two other special TARGET= names are "_self" which makes the link display in the same frame which contains the link (just as if you had left off TARGET=) and "_parent" which makes the link display in whatever <FRAMESET> document contains the frame which contains the link (which is the same as "_top" in this case.) Why are these useful? See the next section... 15.5 More frame stuff Remember <BASE HREF="url">, which specifies the document's own URL so that when it encounters a relative or internal link (<A HREF="#section">) it knows where to go? <BASE HREF> isn't usually necessary -- except in special cases where you move the document without moving the links, and in the very special case of the index.html in your public_html directory on The World -- but there's a related, useful option for <BASE>, namely <BASE TARGET="framename">. Let's rewrite navbar.html: <HTML> <!-- save this as navbar.html --> <HEAD> <TITLE>Navigation bar, Version 3</TITLE> <BASE TARGET="_blank"> </HEAD> <BODY BGCOLOR="#000000" TEXT="#FFFFFF"> <P ALIGN="CENTER"> Do you prefer <A HREF="content.html">Blue</A>, <A HREF="content2.html">Green</A>, or <A HREF="http://www.yahoo.com">Yahoo!</A>? </P> </BODY> </HTML> Now what happens when you view index.html? Even though none of the links has a TARGET= option, the <BASE TARGET="_blank"> applies to all of them, which means that all link open in a new window (useful if you want to be really sure you don't make a para-site by accident.) If the <A HREF="url"> has a TARGET="framename", that overrides the <BASE TARGET="framename">, so we can still have links that open in different frames. Fix the blue and green links so that they open in the frame named "content-frame" and your site should be working like the previous version. (And if you wanted one of the links to open in the same frame as the link, you would use TARGET="_self".) Above I said that there was a TARGET="_parent" which referred to the <FRAMESET> document which contained the link. This is different from "_top" in that "_top" always refers to the main window, while "_parent" is useful in those strange cases where you have nested <FRAMESETS>. Suppose your navbar had a link like this in it: <A HREF="moreframes.html" TARGET="content-frame">...</A> That obviously opens the link in the large frame at the bottom of the window. But suppose this moreframes.html file is not a regular document with a <BODY> but another <FRAMESET> document, which would then fill that lower frame with its own set of frames. You would have one set of frames inside another set of frames. This is fine, if you want to make something really complicated -- and any links within the sub-frames within that bottom frame would use "_parent" to refer to the whole bottom frame (which is now divided), or "_top" to refer to the whole window. Does this make your head hurt? A more useful method for putting one <FRAMESET> inside another is to do it all in your main document, index.html. Let's replace it: <HTML> <!-- save as index.html --> <HEAD> <TITLE>Framed Site, now with more frames!</TITLE> </HEAD> <FRAMESET ROWS="60, *"> <FRAME SRC="navbar.html" NAME="navbar-frame"> <FRAMESET COLS="*, *"> <FRAME SRC="content.html" NAME="content-frame"> <FRAME SRC="content2.html" NAME="content-frame-2"> </FRAMESET> </FRAMESET> <NOFRAMES> <H1>Frameless version of my site</H1> <P>If your browser were showing frames, this site would look different.</P> <P>Check out my <A HREF="content.html">blue page</A> and my <A HREF="content2.html">green page</A>, or look at the <A HREF="navbar.html">navigation bar</A>.</P> The outer is still the same -- two rows (frames), one of which is 60 pixels tall, the other of which is * (the rest of the window). Then the inner is two columns, which show the blue page and the green page side-by-side in the subdivided lower frame of the outer . In other words, we've put frames inside the lower frame. Any links within the two frames at the bottom could use TARGET="_top" to refer to the whole window, "_parent" to refer to the large bottom part of the window, or "_self" or "content-frame" or "content-frame-2" to refer to one of the two frames at the bottom. Why did we have to nest two s to make three frames? Because only takes a ROWS="..." or COLS="..." option but not both. So if you want to divide the window only vertically or only horizontally, you can do that with a single , but if you want to make a tic-tac-toe grid you need one to make rows and another to make columns. Want to try making a nine-framed tic-tac-toe document on your own before I show an example below? Looks messy when you view it (because I didn't turn off all the scroll bars), but it works, it works, hooray! It's three rows, each of which contains three columns. Try grabbing some of the borders between the frames and moving them in your browser. This makes it clear that the page is divided up into rows which are divided into three frames each. Sharp-eyed readers may have noticed that "33%, 33%, 33%" only adds up to 99%. Where did the other 1% go? It doesn't matter because the Web browser is supposed to be smart enough to realize that I'm using fractions of 99 instead of 100. In other words, make all the math errors you want, the browser will still make it add up to the width of the window. By the way, you can't make a contain itself in a frame. Well, you can write that into your HTML, but it'll just display a blank spot because Web browsers check for this to prevent an infinite regression. 15.6 Frame notes When browsing a framed site, you may want to get the URL of an individual frame so you can bookmark it, view its source, or whatever (as opposed to the document.) In some Web browsers, you can right-click (in Windows) or hold down the mouse button (in Mac OS) to get a pop-up menu which may contain "New window with this frame" (which you can then bookmark or view the source of.) Or, you could view the source of the and find the URLs of the various frames. Microsoft Internet Explorer supports another kind of frame,