Sticky menu

This script does not work in iCab and Omniweb.

This script creates a 'sticky' menu on the page that comes along when you scroll the page.

Until position: fixed becomes well supported, the only way to create a sticky menu is to monitor the scrolling of the user and constantly update the position of the menu. The problem here is that this means a JavaScript keeps on running and running as long as the user is on this page.

While modern computers don't mind, on some older ones the script can use so many system resources that the whole computer slows down, something we'd rather avoid. Also, the fixed menu can flicker irritatingly if the user scrolls very fast and the menu adjusts to each scroll.

For these reasons I decided to make the script slow (half a second between checks) and to only adjust the menu if the user has stopped scrolling. Try it by scrolling the page, the menu will adjust at its leisure.

Position: fixed

Theoretically, the way to create a sticky menu is to give it a position: fixed on the page, so that it stays in the correct place regardless of scrolling. However, the fixed position is currently only supported by Explorer 5 on Mac, Opera 5 and Netscape 6, in short, a minority of the users.

For comparision, I also included a fixed layer in this page. You can make it visible. If your browser doesn't support position: fixed the layer shows up at the very bottom of this page.

I'd love to do something like

if (position: fixed supported)
{
	set position to fixed
}
else
{
	use the workaround script
}

but I found no way to check if the browser supports position: fixed (except for a browser detect, but using it would be much too dangerous in the long run).

Therefore I decided to stick to the workaround for the moment.

The script

var menu;
var theTop = 30;
var old = theTop;

function init()
{
	menu = new getObj('menu');
	movemenu();
}

function movemenu()
{
	if (window.innerHeight)
	{
		  pos = window.pageYOffset
	}
	else if (document.documentElement && document.documentElement.scrollTop)
	{
		pos = document.documentElement.scrollTop
	}
	else if (document.body)
	{
		  pos = document.body.scrollTop
	}
	if (pos < theTop) pos = theTop;
	else pos += 30;
	if (pos == old)
	{
		menu.style.top = pos;
	}
	old = pos;
	temp = setTimeout('movemenu()',500);
}

You also need the DHTML micro-API.

Explanation

The script is quite simple. First define some variables.Set theTop, which gives the minimum top of the layer, to 30 (pixels). Set old to the same.

var menu;
var theTop = 30;
var old = theTop;

onLoad, I call this function that initializes the scrolling menu. Set the variable menu to contain the layer (I do this only now because the layer is available only after loading).

function init()
{
	menu = new getObj('menu');

Call movemenu() to start the scrolling.

	movemenu();
}

movemenu()

This is the function that handles everything.

function movemenu()
{

We read out the current position of the page. Of course this is browser dependent. You only need the documentElement bit if you use a DOCTYPE. It's there to make sure that Explorer 6 also executes this script.
(See the Viewport properties page for more information).

	if (window.innerHeight)
	{
		  pos = window.pageYOffset
	}
	else if (document.documentElement && document.documentElement.scrollTop)
	{
		pos = document.documentElement.scrollTop
	}
	else if (document.body)
	{
		  pos = document.body.scrollTop
	}

Now pos contains the current position. We see if pos is smaller than theTop, the minimum. If it is, make it equal to theTop, the layer should not scroll higher.

	if (pos < theTop) pos = theTop;

In all other cases, add 30 to pos because I also want the menu to be 30 pixels from the upper window border.

	else pos += 30;

Now we know where the menu ought to go. Instead of putting it there always, which might create an irritating, flickering effect, we first check if this position is the same as the last time we checked. If it isn't, the user is still scrolling and we do nothing.

	if (pos == old)
	{

If the user does not scroll we put the menu in its new position.

		menu.style.top = pos;
	}

Finally we set old to the current position for comparision the next time we run the function.

	old = pos;

Finally we set a timeout that calls the function after half a second (500 milliseconds) have passed.

	temp = setTimeout('movemenu()',500);
}
This is the comparision menu with position: fixed.
Hide it