RSS Feed Twitter Posts RSS Comments RSS

Sunday, September 20, 2009

Timo's float-drop CSS-only dropdown menu - simplified

Dropper Dropdown Menu:

A refined CSS only dropdown menu
  • The worlds most accessible dropdown menu.
  • It is fixed width for simplification purposes.
  • It is uses no javascript.
  • It is uses no extra html.
  • It is keyboard accessible without javascript.
  • It is cross-browser (tested in: IE5.5-IE8, Firefox, Opera, Safari(PC) and Google Chrome.).
  • This menu is valid css/html.
  • This menu was invented by me, simplified and improved with the help of Paul O'Brien.

more details:

  • It uses margins to hide content.
  • This menu uses float-drop to drop the links into view.
  • IE6 keyboard tab bug fix provided by Paul O'Brien.
  • Tip to use tabindex to add "opera keyboard support" given by Stu Nicholls, now removed as it confused the tabbing order in other browsers.
  • Tip: to access the links with a keyboard in opera, press Ctrl+Up & Ctrl + Down.
  • Tip: to access the links with a keyboard in safari4, enable tabbing in preferences/advanced/press tab to highlight each item on webpage.
  • Max height to hide content is of 303024px (18939em @base 16px) which is the height used on the worlds highest website although a height of 32767px is the recommended maximum that has been tested to be the max in opera and safari.
  • Ugly vibrant colors used on purpose.

Demonstration of the Dropdown:

Example

HTML Code for the full dropdown menu:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>TH - CSS Only Dropdown</title>
<style type="text/css">

.nav, .nav ul {
    list-style-type:none;
    margin:0;
    padding:0;
}
.nav a {
    text-decoration:none;
}
/*IE5 list fix*/
.nav .sub li {float:left;}
.nav .sub > li {float:none;}
#navigation {
    position:relative;
    height:25px;
    background:#ebebeb;
    z-index:10;
}
.nav {
    position:absolute;
    visibility:hidden;
}
.nav .link {
    width:300px;
    margin-top:-10075px;
    float:left;
}
.nav a {
    position:relative;
    display:block;
    height:25px;
    line-height:25px;
    text-decoration:none;
    color:#000;
    z-index:10;
    visibility:visible;
}
.nav .sub a {
    background:orange;
    margin:0 -1px 0 0;
    width:300px;
}
.nav .sub {
    float:left;
    background:#F90;
    padding-top:25px;
    margin-top:-25px;
}
.nav a.main {
    width:300px;
    height:25px;
    line-height:25px;
    margin-top:10075px;
    margin-right:-299px;
    float:left;
}
.nav a.main:hover, .nav a.main:focus, .nav a.main:active {
    margin-right:0;
    background:#000;
    color:#fff;
}
.nav .sub a:hover, .nav .sub a:focus, .nav .sub a:active {
    margin:0 0 0 0;
    background:#333;
    color:#fff;
}
/*empty rule to fix occassional IE6 tabbing bug, one of the weirdest bug's i have seen.*/
a, a:hover, a:active, a:focus {}
/*Opera fix*/
.sub:hover {
    clear:both;
}
</style>
</head>
<body>
<div id="navigation">
    <ul class="nav">
        <li class="link"> <a class="main" href="#m1">Main</a>
            <ul class="sub">
                <li><a href="#1">test1</a></li>
                <li><a href="#2">test2</a></li>
                <li><a href="#3">test3</a></li>
                <li><a href="#4">test4</a></li>
            </ul>
        </li>
        <li class="link"> <a class="main" href="#m2">Main</a>
            <ul class="sub">
                <li><a href="#1">test1</a></li>
                <li><a href="#2">test2</a></li>
                <li><a href="#3">test3</a></li>
                <li><a href="#4">test4</a></li>
            </ul>
        </li>
        <li class="link"> <a class="main" href="#m3">Main</a>
            <ul class="sub">
                <li><a href="#1">test1</a></li>
                <li><a href="#2">test2</a></li>
                <li><a href="#3">test3</a></li>
                <li><a href="#4">test4</a></li>
            </ul>
        </li>
    </ul>
</div>
</body>
</html>

How it works (Visual Example):


content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content : content
The two boxes are floated to the left, if one expands then they both don't fit in the same width making the latter one to drop, thats how float drop is used to achieve the effect, but in the real example we use negative margins to remove 99% of the width, and margin:0 on hover to restore it.

Info:

This dropdown was created because of my hate of javascript based dropdowns.
This dropdown serves to proove that it is indeed possible to create a true css only dropdown.
It took about a month to make the dropdown (from idea to reality), and a week to simplify it with the help of Paul.
It was also featured as a quiz on Paul's CSS quizzes on Sitepoint (my forum's alias is YuriKolovsky).

Update:

To add, if you click a blank link (href="#") it will keep the link open, this is actually a good thing as it can simplify the usability, there is also the side effect in some browsers where if you click a link, and then press the back button to return, the dropdown link will remain highlighted, this is a browser feature, and the only known way to remove it, is to remove tabbing (remove the a:active and the a:focus)

Update2:

people have been asking how to change the width, here is how: change from 300 to 150px wide.
.nav .sub a {
    width:300px;
}
.nav a.main {
    margin-right:-299px;
}

to

.nav .sub a {
    width:150px;
}
.nav a.main {
    margin-right:-149px;
}

Terms of use:

The software referenced within this license is distributed free of charge and free from any warranty. It may be used freely for any purpose whatsoever. The author created and released this work because he is genuinely a Nice Person!

Users are encouraged to use, modify, distribute, improve and otherwise manipulate the code. After all, it’s free.

The author sincerely hopes that end users enjoy and appreciate the hard work that went into creating it, and would appreciate being referenced in future modifications of the code since it was based on the author’s original concept and work.

Users are nonetheless encouraged to provide reciprocity whenever possible as it provides positive reinforcement and encouragement to the author. Furthermore, the minimum reciprocation I ask is to leave a ‘thank you’ comment in the area below:

28 comments:

philsdabom said...

When you click on a link in the sub menu and hit the browser back button to return to the page you were originally on the sub menu is still active/visible. You have to click elsewhere on the page to make it roll back up if you will.

Timo Huovinen said...

yes, you are correct. (added details in post)

christian_steinert said...

This is really nothing short of amazing! What an incredibly good idea - I had been searching for a keyboard-accessible CSS-based dropdown and was slowly starting to think how I could abuse link states to create one that but then I stumbled across this. I will very likely use this method, since I would hate to depend on javascript for basic accessibility and this seems to be the perfect solution.

I hope that this gets blogged about a lot. Have you considered contacting alistapart.com on this - I am sure they would love to publish a short article on this and it would really be good if this method would become known.

I have played around a bit and created my own version of your method, to allow easier resizing and re-skinning of the menu as well as allowing to use different markup (heading for each section with a list below as an alternative to using a two-level nested list. Also, I wanted to make the menu work with headings rather than links for the menu names, since I don't need them to be links. If headings are used, then this has the drawback that IE6 will require additional javascript (which is not present in the sample below) but I can live with that. My code has the disadvantage that it requires to use more class names, since I intended to decouple the CSS is more strongly decoupled from the HTML markup. I have not tested with IE5.x, since I am not serving CSS to it anymore. It works acceptably with IE6-8, Opera, Firefox AND Webkit but I have still trouble with Konqueror.

Timo Huovinen said...

thanks for the comment christian_steinert :)
im very glad that you like it.

no, i haven't thought about contacting alistapart.com but that is indeed a good idea!

yes, this is the only keyboard accessible css only dropdown on the web, and im proud to be the one who thought of it.

my plan was to make it as accessible as possible, basically it works everywhere anytime.

i have not tested in konqueror, so im unsure about that browser.

you can send your version to me directly (timoh89[@]gmailcom) and i will post it here for more people to use, as having a more versions is always good. :)

Atropos said...

What if you have a sub li that need more space than one line? It seems to cut the extra text

Timo Huovinen said...

because of the simplification of code in the dropdown each of the links have a set height, remove the fixed height from the sub link and it will expand with the text (as long as the text has some spaces)

aka add this css to the end:
.nav .sub a {height:auto;}

Rémy said...

Thank you very much. This is really cool without any hacks and conditionals comments.
Great work!

Ken Peel said...

This is really great, really good work Timo.

I would like to do two things with it, but I am struggling.

Firstly, how can I nudge each menu option along 3px so it doesn't but up against the edge of the highlight? I can't seem to put the padding or margin in the right place.

Secondly, how to put a thin border around each option so users can see exactly each box clearly?

I would really appreciate your help!

Timo Huovinen said...

add the border to the links, you can use them as you would normally use them, just make sure to compensate for the border added width.

recap on how it all works:
1. a width is specified for the links.
2. the width is removed "almost" completely from the links using negative margin-right.
3. on hover the negative margin-right is removed.

in the above example the link is 300px wide
so it has a negative margin of 299px leaving 1px

this way you can edit the width, by changing the negative margin too.
if you add a border to the links, then the border counts as additional width.

to nudge the links use padding on the links.

if you wish to support IE5, then add some box model fixes.

regards

Michael said...

Thanks ever so much for this code, it was very useful and interesting and saved me a lot of time. I will no doubt play with the code later on! I'd happily donate to you if you had a donate link!

Simply awesome ;)

Timo Huovinen said...

Thanks Michael :D
I'm currently working on a new dropdown that has no height or width limitations, let's see if it works out, in either case I will soon post the scraps of the idea.

Paolo said...

thank you for making the web a better place. I'm gonna spread the word about you menu ideas!

digital tablet pc said...

great job..
i like it.
thanks for share

rickatucdavis said...

Any way a variable sizing unit (like em) could be used for some or all of the sizing instead of px. I note that doing a text-only zoom causes the menu items to overlap.

Timo Huovinen said...

@rickatucdavis it was simpler in px.

Timo Huovinen said...

Turning it into fully em's did not work too good, Ideally I should make it completely percentage based, and only make the container em based.

Cheknnudol said...

This is excellent! In my application primary links need be narrower than links in the dropdown. In compliant browsers this is straightforward, but in IE8 the dropdown container pushes main links outside of it, pushing subsequent links to the right. Little help?

(The captcha photos are cut off when a comment is more than a couple of lines, so it's nearly impossible to actually post unless you happen to hit tab and scroll it on accident or highlight your way down the area. Resizing the box during editing breaks the text field, also. -chrome 12 PC)

Timo Huovinen said...

@Cheknnudol
yeah sure, I'll have a look, if you can send me an example of what you have so far it would be great, thanks.

p.s. Also thanks for pointing out the captcha flaw (why must everything that I get for free be broken!), to be honest, I didn't even know the captcha was there.

jaect said...

Hey, thanks for this great menu! I am having a problem though: i have a logo image above the navigation bar and it can´t be clicked. When i remove the nav bar, it works again.. Any advice?

Thanks

Timo Huovinen said...

@jaect yes, just give the logo a position and then set it's z-index to above the nav

for example:
#logo {
position:relative;
z-index:100;
}

Deborah G said...

Thank you so much for this code. It was exactly what I needed.

I taught myself HTML (and I'm barely proficient with it) but I could understand your code adapt it to my site. (www.gcoghana.com)

One question, when I use it in Chrome, the top level menu items drop down a bit when I mouse over. It doesn't do it in the other programs.

Again, thank you so much for your time and for sharing your work freely.

Timo Huovinen said...

@Deborah G
add display:inline to .nav .link {}
like so:
.nav .link {
display:inline;
}

GirlsNGlasses said...

That worked perfectly! Thank you. (Did I delete that when I was playing with it? I tell you, I know just enough to be dangerous.)

Mary said...

Will it work on Blogger's new format? Can I put it on an existing horizontal menu? I just need to put it on one link.

YuriKolovsky said...
This comment has been removed by the author.
Timo Huovinen said...

@Mary
Yes, it should work on bloggers new format, if there is no conflicting CSS because of inherited CSS rules and conflicting class/id names.

It is unlikely that there are any conflicts, but I will need to test to be sure.

John Wick said...

not working here any problem

Timo Huovinen said...

@John Wick can you describe what exactly is not working in what browser and OS?

Post a Comment