TJKDropDown Menu
Pushing the Envelope
Do you know about www.Macromedia.com? How do you like the menu system there? What about the links that pop up horizontally under the main navigation menu? I think it's different than the dropdown menus that "pop up " all over the place nowadays.
Enhancements made to the previous version:
- All List Items spread horizontally,
- For better accessibility, I've dropped
visibilityand went for a negativeleftvalue (as in the Suckerfish article), - 2 JS events have been added so it is possible now to tab through the entire menu with MSIE,
- A short script is used to dynamically assign all event handlers,
- An extra style sheet (highlighted code below) and a very short script, both MSIE "specific", have been added to prevent the menu system to fall apart in case "Active Scripting" is disabled.
- The empty string used to swap classes has been replaced with the actual class value of the Top Level
lis (this seems to correct - more or less - a small Safari issue).
I've tried different solutions to hide the sub level uls but left seems to be what works best (MSIE doesn't play ball with z-index and I had trouble using text-indent with NN6).
If you're using only 1 or 2 Top Level Links to trigger sub links, you may think that #3 is not necessary better than assigning the events directly through the markup; and you may be right in term of "footprint". But it is a good habit to separate behavior from structure.
This is the content of our 2 CSS files:
This first file shows the negative left value technique that replaces visibility:hidden
/* all lists */
#TJKDropDownMenu a,
#TJKDropDownMenu a:link,
#TJKDropDownMenu a:visited {
font-size:.9em;
color:navy
}
#TJKDropDownMenu,
#TJKDropDownMenu ul {
padding:0;
margin:0 0 0 6px;
width:750px
}
/* Nested ULs */
#TJKDropDownMenu li ul {
position:absolute;
top:1.8em;
left:-900px
}
/* All LIs */
#TJKDropDownMenu li {
float:left;
width:auto;
margin:0;
padding:0;
list-style-type:none;
font-weight:600;
border-bottom:1px solid #004284
}
#TJKDropDownMenu li a {
padding:.1em .4em;
height:2em;
line-height:2em;
border-bottom:2px solid #e6ecf3;
background:url(/articles/dropdown/img/pipe.gif) right center no-repeat transparent
}
#TJKDropDownMenu li a:hover {
background-color:#004284;
background-image:none;
color:#fff;
border-bottom:2px solid #004284
}
#TJKDropDownMenu li ul li a {
line-height:1.7em;
height:1.7em;
font-weight:400;
border:none;
color:#333;
background-image:none
}
/* we reset the margin for the children */
#TJKDropDownMenu li ul li {
margin:0;
border-bottom:0;
border-right:1px solid #004284
}
#TJKDropDownMenu li:hover ul,
#TJKDropDownMenu li.msieFix ul {left:9px}
The purpose of this second style sheet is to make sure our menu is well formatted when viewed in MSIE when Active Scripting is disabled. So to hide the following rules from "decent" browsers and to call the sheet only when "Active Scripting" is disabled, we do 2 things:
- We use the star html selector to target MSIE only.
- We use a short JavaScript statement to disable that sheet.
* html #TJKDropDownMenu li ul {
margin:0;
position:relative;
left:9px;
top:0
}
* html #TJKDropDownMenu li {border-bottom:0}
* html #TJKDropDownMenu li.trigger {width:250px}
* html #TJKDropDownMenu {background-color:#e6ecf3}
Additions to the Markup:
Before the </head> tag of the document:
<style type="text/css" media="screen">
<!--
@import url(/css/basic.css);
-->
</style>
<link rel="stylesheet" href="/css/msie.css" type="text/css" />
<script type="text/javascript" src="/js/turnoffmsiecss.js"></script>
<script type="text/javascript" src="/js/js4msie.js"></script>
<!--[if IE 5]>
<style type="text/css" media="screen">
* html #TJKDropDownMenu li ul {top:2.2em}
* html #TJKDropDownMenu li ul li a {line-height:1.4em;height:1.4em}
</style>
<![endif]-->
Content of the 1st external JavaScript file (turnoffmsiecss.js):
<!--
if(document.styleSheets) document.styleSheets[1].disabled=true
//-->
Note that no matter how many "@import" statements we have inside the style tags pair, only the first one feeds the array. For example, if we had 3 sheets in the same style container, the value inside the brackets would still be 1.
This is the 2nd external JavaScript file (js4msie.js), this one writes the event handlers for us. This script also makes tabbing navigation possible through the menu:
<!--
// Copyright (c) TJKDesign - Thierry Koblentz
// Setting all the Event Handlers Dinamically
function swap(){this.className="msieFix"}
function swapBack(){this.className="trigger"}
function swapfocus() {this.parentNode.parentNode.parentNode.className="msieFix"}
function swapblur() {this.parentNode.parentNode.parentNode.className="trigger"}
function TJKSetEvents(){
if (document.getElementById){
var LI = document.getElementsByTagName("li");
var zLI= LI.length;
for(var k=0;k<zLI;k++){
if(LI[k].parentNode.parentNode.className=="trigger"){LI[k].firstChild.onfocus=swapfocus;LI[k].firstChild.onblur=swapblur}
if(LI[k].className=="trigger"){LI[k].onmouseover=swap;LI[k].onmouseout=swapBack}
}
}
}
//-->
We use the onload attribute of the <body> tag to call TJKSetEvents():
<body onload="TJKSetEvents()">
We plug below the body tag a MSIE CC inside a noscript tags pair to take care of the IE5 broken box model in case the second sheet is used (if "Active Scripting" is disabled):
<noscript>
<!--[if IE 5]>
<style type="text/css" media="screen">
* html #TJKDropDownMenu li ul {top:0}
* html #TJKDDM #current ul {top:0}
* html #TJKDropDownMenu ul a:hover {line-height:17px}
</style>
<![endif]-->
</noscript>
Replacing the onmouseover/onmouseout events with a class attribute in the Top Level lis used to trigger Sub Links:
<li class="trigger"><a href="javascript:;">About Us</a>
Et VoilĂ !



















