Talk is cheap. So is storage space.
Then why bother? I tell you why.
( 'Cause talk is cheap.)

Dynamic Menu Under 10k


I
N
T
R
O

alk is cheap. So is storage space. You can easily find a provider who is willing to host your Web site for free, if your site is smaller than 50 Megabytes. How much is 50 Megs? For comparison, the text of those books that an average person reads during a lifetime would easily fit in 50 Megabytes. Dealing with pictures is a different story. One good quality photo may take as much storage space as the full text content of a book.

till, one can build a nice and graphically rich site within the free size limits. The problem starts when you happen to be lucky and people start to visit your site. After a certain amount of traffic the provider will ask you to pay for the bandwidth and the free site is not free anymore. Keeping the site small keeps the necessary bandwidth small and you from becoming a paying customer. OK, you may say. On the other hand, if you don't show storage-extensive graphics, your site stays free of charge because it is so unattractive that nobody wants to see it. Right? Wrong. Your visitor's first impression greatly depends on the loading time of your opening page.

Many pages on the Web take much more storage than they should. Let's take a simple menu bar of four selection buttons created graphically. A button may have three versions: one for normal, one for pressed state and a third for the state when the mouse is over the button. A simple graphical button may have the size of 2k at least. So, the four buttons with three versions easily occupy 24k. With a regular modem connection, loading 24k takes about 5 seconds. 5 seconds of your visitor's time and of your bandwidth.

There is a good old programming principle that is forgotten by many Web designers: Repetition should be managed with a loop rather than repeating a chunk of code. The blame is not necessarily on the developer. Pure HTML is not capable to manage loops. But JavaScript is. Displaying a bar of four dynamic buttons should not require four times as many graphics and four times as big code. Showing three different versions of a button may add one small image of the altering part only. In the following I show you a solution for the above menu bar problem. It will display graphical buttons with the above three states. The number of selection buttons can be arbitrary and the required amount of transfer stays below 10k, regardless of the number of buttons. Adding a new button would add a few bytes, but not kilobytes to the transferrable file.

Let's create an opening page with two frames. The top frame will contain the menu bar and the selected page will appear in the bottom frame.

<html>
  <head>
      <meta http-equiv="content-type" content="text/html;">
      <title>Home frame</title>
  </head>
  <frameset rows="90,*" border="0" framespacing="0" frameborder="no">
      <frame src="top_frame.html" name="menu" scrolling="NO" noresize>
      <frame src="page0.html" name="content" noresize>
  </frameset>
</html>

Code 1. index.html

When you modify top_frame.html, set the highlighted size of the first frame the way that the bottom of the frame coincide with the bottom of the tabs. For the present height of top_frame.html, the above value works well in Internet Explorer 6, Netscape 6 and Opera 7. Here is the code of the top frame:

<html>
    <head>
        <title>Top Frame for Choices</title>
        <meta http-equiv="content-type" content="text/html;">
        <link href="menuDrawerStyle.css" type="text/css"
              rel="stylesheet">
        <script language="JavaScript" src="scripts/menuDrawer.js">

        </script>
        <base target="content">
    </head>
    <body>
        <h1>Home Page</h1>
        <table cellSpacing="0" cellPadding="0" border="0">
            <tr>
                <script language="JavaScript">DrawMenu();
                </script>

            </tr>
        </table>
    </body>
</html>

Code 2. top_frame.html

top_frame.html is as simple as index.html. Its head contains a link to a style sheet and a link to a JavaScript file. Its body contains a table with cells holding the images of the menu tabs. They are created via calling the JavaScript function DrawMenu(). The fun starts with the JavaScript:

//menuDrawer.js ver.1.0
//Creates tabs in a menu frame to switch content in a center frame.

//Author of version 1.0: L. Naszodi Jan. 14. 2004

// You are allowed to use and modify the code freely but the author
// of the original version must be mentioned in a comment.

var tabSelected = 1;
tabText = new Array();
//Your set of menu items come here:
tabText[0] = 'Applications';
tabText[1] = 'Publications';
tabText[2] = 'Favorite Links';
tabText[3] = 'About Me';

function changeSelected(tab) {
    if (tab!=tabSelected) {
        //Change previously selected tab back to non-selected:
        objID='obj'+tabSelected;
        document.getElementById(objID).src='images/toprightNotSel.png';
        //Change newly selected tab to selected:
        objID='obj'+tab;
        document.getElementById(objID).src = 'images/toprightSel.png';
        tabSelected = tab;
    }
} //end function changeSelected()

function DrawMenu() {
 with (document) {
  for (var i = 0; i < tabText.length; i++) {
    writeln('<td>');
    writeln('    <table cellPadding="0" cellSpacing="0" border="0">');
    writeln('        <tr">');
    writeln('            <td>');
    writeln(' <img src="images/topLeft.gif"></td align="bottom">');
    writeln('            <td class="tabtop"> </td>');
    write('            <td>');
    write('<img id="obj'+i+'" align="bottom" src="images/');
    if (i==0)
        write('toprightSel.png">')
    else
        write('toprightNotSel.png">');
    writeln('</td></tr>');
    writeln('        <tr>');
    writeln('            <td class="tableft"> </td>');
    writeln('            <td class="tabmid">');
    writeln('<a onclick="tab='+i+';changeSelected(tab);"');
    writeln(' href="option'+i+'.html">'+tabText[i]+'</a></td>');
    writeln('            <td class="tabright"> </td>');
    writeln('        </tr>');
    writeln('    </table>');
    writeln('</td>');
  } //end for
 } //end with
} //end function DrawMenu()

Code 3. menuDrawer.js

For the tab-like buttons I used six small images, with a total size of about 1k. The names of the first three are highlighted here, the other three show in the style sheet as background images. Only the top right segment of the tabs changes when one or another tab is selected, and only this segment has two versions that swap when a tab is selected. In function changeSelected(tab) the image objects are referenced by their ids, rather than by their names. This way the site works in Netscape 6, too, not just in Internet Explorer 6 and in Opera 7. In the latest W3C recommendations of migrating pages to XHTML, a stricter HTML, names have been completely expelled. You can read a short introduction of XHTML in this book.

At some places I had to use the document.write() function instead of document.writeln(). It is very important not to place a white space (a new line) between the tags <img> and </td>. If you do, the images of the buttons will disintegrate to their graphical elements in IE and in NS.

Here is the last piece of code, the linked style sheet file of our project:

/* menuDrawerStyle.css version 1.0
creates tabs in a menu frame to switch content in a center frame.

Author of version 1.0: L. Naszodi Jan. 14. 2004

You are allowed to use and modify the code freely but the author
of the original version must be mentioned in a comment. */

body{margin:5px 5px 0 50px;/*top right bottom left */
    padding:0 0 0 0;
    font-family:'Times New Roman',Times, serif; font-weight:bold;
    font-size:14pt; text-align: left;
    background: url(images/tagEdge.gif); background-repeat:repeat-x;
    background-position: bottom; line-height:100%;}
h1 {background-color: lightblue; text-align: center; font-size:20px;}
a { font-size: 18px; font-weight: bold; text-decoration: none;
    margin: 0 0 0 0; padding: 0 0 0 0; border: 0;
    text-decoration: none; }
a:hover { background: silver; color: darkblue;}
td.tabtop { background-image:url(images/topbar.gif);
        background-repeat:repeat-x;}
td.tabright{background-image:url(images/rightSidebar.gif);
        background-repeat:repeat-y}
td.tableft {background-image:url(images/leftSidebar.gif);
        background-repeat:repeat-y}
td.tabmid {background: white;/*whitens the body's background-image*/}

Code 4. menuDrawerStyle.css.

To avoid transferring more graphics, the effect of the mouse-over event is handled by the a:hover style element. It works very well in all the three investigated browsers.

One minor and one major change is necessary to customize the tool:

  1. At the beginning of menuDrawer.js, change the values of tabText[ ] array to the texts that you want to show on the tabs. No dimensioning is necessary. Just start the indexing from [0], give them the captions of the tags, and the code will know the number of tabs to create.
  2. Write your content in page0.html, page1.html, etc. Sorry, you're on your own here. I can't do this for you.

Done? Then you have a complete dynamic menu-driven Web page. The rest of changes is a matter of taste. For example:

  1. The widths of the tabs are variable, depending on their captions. I like the way it is but if you don't, just put a couple of &nbsp; (hard spaces) to the front and the end of the texts of the tabText[ ] array, for example, in the short 'About Me' caption, and the tab widths become about uniform.
  2. Do you want to change the image of tabs while the mouse passes over them? Modify the a:hover entry in the style sheet. However, avoid any modifications that change the size of the text. Otherwise the altering size will make the graphics jumpy.

Good luck, and let me know about your improvement ideas.

Summary

The suggested semi-graphical menu bar avoids lengthy opening of your Web page. The buttons have all the usual dynamics, such as change at mouse over, mouse out and click events. The number and size of applied images and the size of reusable code are very small regardless of the number of menu elements.

Problem

  • Because of deductical and historic reasons, the above solution uses a table for arranging the buttons of the menu. Rewrite the solution so that it use div tags instead of table elements.