Clickdrop menu

This is one way to make a menu that you can click to reveal submenus. It uses javascript, but it degrades to a simple list with sublists for those without javascript.

The menu itself is built with PHP - mostly so that we can show the current page, as in my Showing current page demo.

This is what I'm talking about. It looks very basic, but that's because I want to get the idea across with as little code as possible.

Here's the code on the index page of this demo:

PHP
<?php
$page="index";
$pagetitle="clickdrop home";
include 'clickdrophead.php';
?>
<body>
<?php include 'clickdropmenu.php'; ?>
</body>
</html>

You can see that the first things are to identify the name of this file (index) and the actual title of the page (clickdrop home). After that, the head is included.

Here's the head:

PHP
<?php include 'menu-config.php'; ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Clickdrop : <?php echo $pagetitle; ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript" src="clickdrop.js"></script>
<link href="clickdrop.css" rel="stylesheet" media="screen" type="text/css">
<?php
if (in_array($page,$link[1])) {$show=$topic[1];}
elseif (in_array($page,$link[2])) {$show=$topic[2];}
elseif (in_array($page,$link[3])) {$show=$topic[3];}
if ($clickdropbiscuit) {
echo '
<style type="text/css">
<!--
#clickdrop ul {
display:none;
}
#clickdrop ul#'.$show.' {
display:block;
}
-->
</style>
';
}
else {
echo '
<script type="text/javascript">
<!--
window.onload=function(){
switch1('; if($show) {echo "'$show'";} echo ');
makeBiscuit(\'clickdropbiscuit\',\'yes\',10);
}
//-->
</script>
';
}
?>
</head>

You can see at the top of the head, that 'menu-config.php' is included first. I've split the menu code up into two files - a configuration file and the part which actually builds the menu.

The 'menu-config.php' file looks like this:

PHP
<?php
$topic=array('index','one','two','three');
$topictext=array('Home','One','Two','Three');

$link[1]=array('one-a','one-b','one-c');
$text[1]=array('One A','One B','One C');

$link[2]=array('two-a','two-b','two-c');
$text[2]=array('Two A','Two B','Two C');

$link[3]=array('three-a','three-b','three-c');
$text[3]=array('Three A','Three B','Three C');
?>

The $topictext array has the text of the top level of the menu. The names of the id's given to the submenus are in the $topic array. The 'Home' page obviously won't have a submenu, so the link (index) goes there instead of a submenu id.

Arrays start at '0', so the first submenu ('one') is number '1' in the array. The links and text for submenu 'one' are in the $link[1] and $text[1] arrays. So far so good.

The next thing in the 'head' file is the DTD, which is essential to any good web page. After that is the actual head with the title tags. The $pagetitle which was set at the top of the page is inserted here. The rest of the 'head' file I'll come back to later.

The next thing to look at is the menu itself...

PHP
<?php
echo '<ul id="clickdrop">
';
$i=0;
while($i < count($topic)) {
echo "<li". (($page==$topic[$i]) ? ' class="current"' : '') . "><a href=\"".((count($link[$i])>0)? "#n\" onclick=\"switch1('$topic[$i]')\"" : $topic[$i].".php\"").">$topictext[$i]</a>
";
if (count($link[$i])>0) {
echo "<ul id=\"".$topic[$i]."\">
";
$j=0;
while($j < count($link[$i])) {
echo "<li". (($page==$link[$i][$j]) ? ' class="current"' : '') . "><a href=\"".$link[$i][$j].".php\">".$text[$i][$j]."</a></li>
";
$j++;
}
echo "</ul>";
}
echo "</li>
";
$i++;
}
echo "</ul>
<p>$pagetitle</p>
";
?>

This is two 'while' loops - one within the other. The outside loop goes through the first things in the config file - the top-level things. First, it checks to see if the link name is the same as the name of the present file - if it is, it inserts 'class="current"' into the 'li' tag. Then, if there is an associated array of sublinks, it will set the link as "#n" (to prevent the page from jumping to the top when the link is clicked) and insert 'onclick="switch1(...)"' with the id of the relevant submenu in the parentheses. This is for the javascript that controls the whole click-drop effect. If there is no associated submenu, it will insert the link we want - in this case, the top-level text 'Home' will be linked to 'index.php'. If there is a submenu - as there is here for three of the top-level items - that will then be built by the inner loop. As with the top level, it will check to see if the link is the same as the current page and if it is, insert 'class="current"' into the 'li' tag.

(The last part which inserts the $pagetitle into a paragraph is just for this demo).

So the menu's built. Now, we can have a brief look at the javascript which controls the clicky-thing (it's linked to in the head)...

javascript
function switch1(div) {
var option=['one','two','three'];
for(var i=0; i<option.length; i++) {
if (document.getElementById(option[i])) {
obj=document.getElementById(option[i]);
obj.style.display=(option[i]==div)? "block" : "none";
}
}
}

This is explained elsewhere so I don't want to say too much here, but basically it hides and shows the submenus.

The CSS for this demo is very simple:

CSS
a {
color:blue;
}
.current a{
color:red;
}

The problem then is that if you do what I've explained so far and then load the page in a browser, you'll have all the submenus showing until one of the top-level links is clicked, when the two other submenus will be hidden. That will happen again if you actually go to another page. The question then is 'what's the best way to avoid that?' Well, using a javascript onload event to hide the submenus is one good option. The problem then, though, is that when the page loads, you'll briefly see the whole menu - all the submenus - until the javascript kicks in and they disappear. It can be quite irritating.

A better option is to use CSS to hide the submenus we don't want to see. The problem then is that if javascript is not available to the user, the submenus will be completely inaccessible - unless they switch the stylesheet off too.

My solution to this conundrum is to set a cookie with javascript and read it with PHP. On first load, the cookie will be set by the javascript - if the browser has javascript enabled. When the page loads, the PHP checks for the cookie. If it's not there, it's either the first visit, in which case we try to set the cookie and try to hide the submenus with the onload event, or it's not the first visit, but the cookie's not there because javascript was not enabled last time. Either way, we don't use CSS to hide the submenus. If the cookie is there, we don't need the onload event or to set a cookie, we can just put some CSS in the head of the page to hide the submenus and the menu works smoothly.

I got the cookie script from Quirksmode (thank you).

Of course, this is not a foolproof method - some people may switch javascript on and off at random, but I doubt it. Anyway, I set the cookie for just ten days, so, even if there is some-one like that, she will only be inconvenienced for ten days at most.

You can download the files used in this demo here.

Finally, a bit of a disclaimer... This code/script works well, but I have no idea what 'the best way' to do this is and I'm really no expert. If anyone wants to tell me that this is a waste of space and/or it can be done much more easily another way, I'm all ears.

Comments

#1
2006-01-28 Ben Sharp says :

This is a useful menu and I shall use it on my site. Thank you.

#2
2006-01-28 BonRouge says :

Ben: That's good to hear. Thanks.

#3
2008-07-10 Sam says :

Hi BonRouge,
How do you make one of the selection to selected and submenu visible, e.g. "one" has three sub-item and I want that to be selected and sub-menu visible on page load. Thanks. Sam

#4
2009-09-16 Orbosphere says :

Is there a way to use different background images for each of the <li> list items? I want to use separate images for each button, along with rollover and selected images. I'm not sure if I can do this since the list is generated in while loops.

Comment form

Please type the word 'wolf' here:

BB code available :

  • [b]...[/b] : bold
  • [it]...[/it] : italic
  • [q]...[/q] : quote
  • [c]...[/c] : code
  • [url=...]...[/url] : url