As the site menus expand, the need for a drop-down system becomes more apparent. These are the problems:
- We must have something that works without JavaScript being enabled (so "pure" CSS).
- It must survive font resizing.
- It must work in IE7 (which means there must be more than pure CSS, because IE7 CSS positioning is screwy).
- It must degrade gracefully on IE6.
- It must be functional with no CSS or JS at all.
It took me all day, but I got there. The CSS is fairly straightforward, and conditions 1 and 2 are satisfied on all the decent browsers by that. However, to position the submenus correctly in IE7, I needed to add some extra code in, which I included in a conditional comment:
<!--[if IE 7]>
<script type="text/ecmascript" src=" textresizedetector.js"></script>
<script type="text/ecmascript">
// <![CDATA[
window.onload = startUp;
function findPos(obj) {
var curleft, curtop;
curleft = curtop = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft
curtop = obj.offsetTop
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft
curtop += obj.offsetTop
}
}
return [curleft,curtop];
}
function fixMenuPositions(){
var uls = document.getElementsByTagName('ul');
for (var i=0; i<uls.length; i++){
if (uls[i].className == 'mainMenu'){
var lis = uls[i].getElementsByTagName('li');
for (var j=0; j<lis.length; j++){
if (lis[j].getElementsByTagName('ul').length > 0){
var anc = lis[j].getElementsByTagName('a')[0];
var ancPos = findPos(anc);
var sub = lis[j].getElementsByTagName('ul')[0];
sub.style.left = (ancPos[0] + 1) + 'px';
sub.style.top = (ancPos[1] + parseInt(anc.offsetHeight)) + 'px';
}
}
}
}
}
function init(){
var iBase = TextResizeDetector.addEventListener(fixMenuPositions, null);
//alert( "The base font size = " + iBase );
}
function startUp(){
fixMenuPositions();
/* id of element to check for and insert test SPAN into */
TextResizeDetector.TARGET_ELEMENT_ID = 'theBody';
/* function to call once TextResizeDetector was initialized */
TextResizeDetector.USER_INIT_FUNC = init;
}
// ]]>
</script>
<![endif]-->
The resize detector code is taken from a library I found on the Web, by Lawrence Carvalho. What this does is detect when the font size changes in the browser (when the user resizes it), and you can use that event to re-trigger the layout code which positions the menus correctly. So far so good; condition 3 is now satisfied.
Next, the IE6 issue. Here, there's no point in trying to get the submenus working; my plan for the site is that when you click on a top-level menu item, you'll get the complete page with all subdivs rendered, but if you click on a sublevel item you'll get just that bit. This means that only having the top level menu items still makes all the info accessible, so the thing to do is remove all the submenus completely:
<!--[if lt IE 7]>
<script type="text/ecmascript">
// <![CDATA[
window.onload = removeSubmenus;
function removeSubmenus(){
var uls = document.getElementsByTagName('ul');
for (var i=0; i<uls.length; i++){
if (uls[i].className == 'mainMenu'){
var subs = uls[i].getElementsByTagName('ul');
for (j=subs.length-1; j!=-1; j=j-1){
subs[j].parentNode.removeChild(subs[j]);
}
var lis = uls[i].getElementsByTagName('li');
for (var j=0; j<lis.length; j++){
lis[j].style.display = 'inline';
}
}
}
}
// ]]>
</script>
<![endif]-->
Note the buggering about to get a decrementing loop working when you're inside a comment (so > and -- are not allowed).
So the basic problems are now solved. Next, I need to look at spitting out these menu structures from the actual site.xml code.