RSS Feed Twitter Posts RSS Comments RSS

Wednesday, August 26, 2009

CSS Only Cross-Browser DropDown menu with tabbing (Valid HTML and Free to use)

My CSS Only Cross-Browser DropDown Menu (100% valid HTML, Tested in IE5.5-IE8, Firefox, Opera, Chrome, Safari)

with tab button support and no JavaScript

Live Demo
this demo has no javascript involved at all, neither does it have any ugly tables
Background info
some months ago i started to work on a major website, that required a dropdown menu, now i can honestly say, i hated dropdown menu's, because they would need javascript to work, sure the usage of IE5-IE6 is no longer that large, especially ie6 users with js turned off, but its still possible, and i do not like the idea of having a critical part of my website not work in my website, so after reading a million posts on the internet saying this is impossible i made it my duty to make it work, after thinking for some time, i realized that general relativity was the answer, because it also applies to websites css/html, and used that as the basis on making this css dropdown work in all browsers


The Problem
Internet Explorer <=6 does not support the :hover pseudo state on anything except links that have a valid href="#", for example: <a href="#link">link</a> , so we cannot have a hover state on a div that contains all the dropdown links in IE6, there are some cool (and very dirty solutions) that i will link on the end of the post
The Solution
Everything in websites consists of positioned boxes, each box also has an effect on another box, for example the box below it.
now we can position a div with the dropdown links (sub-links) below a link, then add position:absolute; the div with the sub-links, and then add a margin-bottom:200px; or border-bottom:dashed transparent 200px; to the link on its hover state

<style type="text/css">
a:hover {
  border:bottom solid red 100px;
}
div {
  position:absolute;
}
</style>

<a href="#link">link</a>
<div>
<ul>
<li>link 1</li>
<li>link 2</li>
<li>link 3</li>
</ul>
</div>


, and the link will move the div below it, and this happens in every browser identically. (except opera at times, opera seems to ignore the margin, and thus you can either use a average dropdown method or use borders to push the div down).

Now this is great and all, but what about the sub-links that are inside that you hover over? the menu will immediately hide when you move your mouse away from the main link.
now this was a big problem at the start, but because anything is possible in css, and as long as something is being hovered i can do anything to the website, i found a solution.

each dropdown sublink in the div below the main link is being floated against a shifter div (thats what i called it), basically the links are pressed against a very high but very thin shifter div that will make them "float drop" in case that the one of the sub-links expands (increases width).

so one main link moves the absolutely positioned div that contains the sublinks dropdown, in which each and every link has the ability to do the same.
Cons
  • ¦ the mouses path from the main link to any of the sublinks must remain on top of some link
  • ¦ requires extra div's per link, one for shifter one for containing the sub-links
  • ¦ the dropdown links have to have a fixed (defined) with
  • ¦ the height of the main link has to be fixed (defined)
  • ¦ a little dirty example (will post a better example soon)
  • ¦ has quirks when hovering and tabbing at the same time.
  • ¦ requires some IE5-6 specific css (can be made to work without conditional comments)
  • ¦ the dropdown block needs to have a fixed height (usually min screen height of supported screen sizes. this applies only to ie5-6)

Pros
  • ¦ It's Free
  • ¦ Works in all browsers using only CSS without browser specific html
  • ¦ Completely valid HTML/CSS (semantically correct xhtml/css) and can be made to work without any IE hacks (will give example later)
  • ¦ Has natural tabbing, tabbing works just like that, tabbing can be easily disabled by removing the :focus and :active from the CSS.
  • ¦ JavaScript can be added to improve user experience
  • ¦ Works great and smooth in all browsers


The Idea
The idea itself of general relativity in websites can be taken to much higher and interesting lengths, and this is simply a small example that demonstrates that this area of css has not yet been explored.



Example ready made Code

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>valid browser overflow test</title>
<style type="text/css">
a {
color:#000;
}
.navigation {
height:2em;
width:56.25em;
background:#efefef;
}
.link {
height:2em;
position:relative;
float:left;
z-index:10;
}
a.main {
position:relative;
display:inline-block;
text-decoration:none;
line-height:2em;
height:2em;
z-index:10;
}
a.main b {
position:relative;
display:inline-block;
padding:0 .5em 0 .5em;
line-height:2em;
cursor:pointer;
}
.sublinkscontainer {
position:absolute;
}
.sublinks {
position:relative;
float:right;/*can be any float*/
margin-top:-2em;
}
.sublinks a {
display:block;
background:orange;

padding:.2em 0 .2em 0;
text-decoration:none;

}
.shifter {
position:relative;
float:right;
}
.sublinks .bgthing {
height:2em;
background:orange;
display:block;
}

ul, li {
margin:0;
padding:0;
list-style:none;
}




/*height limit*/
.link {
top:-25em;
}
a.main {
top:25em;
}
a.main:hover, a.main:active, a.main:focus {
margin-bottom:25em;
background:#000;
color:#fff;
outline:none;
}
a.main:active b, a.main:focus b {
outline: dotted thin;/*resetting the outline*/
}
.sublinkscontainer, .shifter {
height:25em;
}
/*valid browser height maximization*/
.nav > .link {
top:-1000em;
}
.link > a.main {
top:1000em;
}
.link > a.main:hover, .link > a.main:active, .link > a.main:focus {
margin-bottom:1000em;
}
.link > .sublinkscontainer, .sublinkscontainer > .shifter {
height:1000em;
}
/*/valid browser height maximization*/


/*width limit*/
.sublinkscontainer {
width:12.563em;
}
.sublinks a {
width:12.5em;/*12.5 - padding*/
}


.sublinks a:hover, .sublinks a:active, .sublinks a:focus {
margin-right:0.063em;
background:#333;
color:#fff;
}
.sublinks:hover a {/*opera fix*/
margin-right:0.063em;
}
a.main:focus + div .sublinks a, a.main:active + div .sublinks a {/*valid browser tab+hover fix*/
margin-right:0;
}

.shifter {
width:0.063em;
}
.sublinks .bgthing {
width:12.5em;
}



.content {
clear:both;
}



a.main span {/*this nullifies the masks effects*/
position:absolute;
right:0;
top:0;
line-height:0;
}
a.main span i {/*the mask*/
display:block;
position:absolute;
width:12.5em;
background:#efefef;/*must be bg color for masking*/
height:2em;
top:0;
right:auto;
}



.hidehotspot {
position:relative;
float:left;
background:red;
height:2em;
z-index:10;
}
.hidehotspot b {
position:absolute;
background:#efefef;
height:2em;
width:56.25em;
display:block;
}


/*ie5 fault for not supporting paddings on links*/
.sublinks a b {
font-weight:normal;
position:relative;
padding-left:.5em;
display:block;
}

/*valid browser height fix*/
.link > a.main:hover,
.link > a.main:active,
.link > a.main:focus {
margin-bottom:0;
}
.link > a.main:hover + div .sublinks a,
.link > a.main:active + div .sublinks a,
.link > a.main:focus + div .sublinks a {
margin-right:0.063em;
}
/*/valid browser height fix*/
</style>

<!--[if lte IE 6]>
<style type="text/css">
.link {
margin-bottom:-2000px;/*only for ie5-6*/
}
/*ie5 fix*/
li {
float:left;
}
.nav {/*only ie5-6 need this*/
height:25em;
position:absolute;
width:56.25em;
overflow:hidden;
}
</style>
<![endif]-->
</head>
<body>
<div class="navigation">
<div class="nav">
<div class="link">
<a class="main" href="#MAIN"><b>MAIN LINK</b><span><i> </i></span></a>

    <div><!--IE6 needs this div-->
<div class="sublinkscontainer">
<div class="shifter"></div>
<ul class="sublinks">
             <li class="bgthing"> </li>
     <li><a href="#test1"><b>test test</b></a></li>
         <li><a href="#test2"><b>test test test test test test test test test test test test </b></a></li>
         <li><a href="#test3"><b>test test</b></a></li>

         <li><a href="#test4"><b>test</b></a></li>
         <li><a href="#test5"><b>test test</b></a></li>
</ul>
</div>
</div>
</div>
<div class="link">
<a class="main" href="#MAIN"><b>MAIN CAN BE LONG</b><span><i> </i></span></a>

    <div><!--IE6 needs this div-->
<div class="sublinkscontainer">
<div class="shifter"></div>
<ul class="sublinks">
             <li class="bgthing"> </li>
     <li><a href="#test1"><b>test test</b></a></li>
         <li><a href="#test2"><b>test test test</b></a></li>
         <li><a href="#test3"><b>test test</b></a></li>

         <li><a href="#test4"><b>test</b></a></li>
         <li><a href="#test5"><b>test test</b></a></li>
</ul>
</div>
</div>
</div>
<div class="link">
<a class="main" href="#MAIN"><b>MAIN</b><span><i> </i></span></a>

    <div><!--IE6 needs this div-->
<div class="sublinkscontainer">
<div class="shifter"></div>
<ul class="sublinks">
             <li class="bgthing"> </li>
     <li><a href="#test1"><b>test test</b></a></li>
         <li><a href="#test2"><b>test test test test test test test test test test test test </b></a></li>
         <li><a href="#test3"><b>test test</b></a></li>

         <li><a href="#test4"><b>test</b></a></li>
         <li><a href="#test5"><b>test test</b></a></li>
</ul>
</div>
</div>
</div>


<div class="hidehotspot"><b> </b></div>
</div>

</div>

<div class="content">
stuff<br />
stuff stuff stuff
</div>
</body>
</html>


Other available dropdowns
I found this post after i made my dropdown, i was slightly dissapointed that my css dropdown was not the first pure css dropdown, Notice that only one of them is pure CSS, it involved very dirty/invalid/heavy code, and does not support tabbing.

i will post more examples of how this method of relative html can be used to make very interesting css features.


Stu Nicholls has designed his own version of this dropdown

Copyright info
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:

14 comments:

Alex said...

How can I change the width of the tabs without breaking anything?

Timo Huovinen said...

these are supposed to be auto adjustable to the text's width.

i made a better version, where you can manually adjust everything
http://thinkhtml.blogspot.com/2009/12/manually-adjustable-float-drop.html

Alejandro Maximiliano said...

Hi, Timo! Inspired by your example I have developed the following menu: http://aranedaalejandro.wordpress.com/
It is an accordion-style menu. The latest version has sliding effect. All with valid stylesheets and markup (SMIL sliding effect for IE).

Timo Huovinen said...

@Alejandro Maximiliano
I'm very glad that it has helped you! :D as that is the sole reason of why I posted it.

Estoy muy feliz de que te haya ayudado! :D que es la única razón de por qué lo he publicado.

Filip said...

I am having one issue when linking to the css rather than styling in the HTML. The menu breaks down. The sub menus are immediately shown in Firefox 3 and IE 8. I removed any IE 5/6 fixes as well. Any thoughts on why?

This was exactly what I am looking for though. Thank you for posting it.

Timo Huovinen said...

@Filip
it's most likely some other styling that you have that is affecting it, it could be the default padding in "ul" which in my case is removed with a quick hack * {margin:0;padding:0;}
remove other styles and check again, or send me a link to your site.

Filip said...

Thanks Timo. The padding in "ul" was the issue. I have to specify the quick hack in the menu CSS sheet in addition to my default style sheet for some reason but it works.

One final thing I noticed is that the menu breaks in Chrome including the example on your website. No sub menu appears.

Timo Huovinen said...

Ah damn, chrome must have updated something...
Until I fix this (which might take a while) I suggest you use Stu Nicholls adaptation of the newest idea I had about dropdowns.
Inline-block dropdown

or the simplified version of this menu that is a lot less tricky and buggy

Filip said...

Thanks for the info. Timo!

Ingo said...

Opera also updated something - all menus dropped down at the same time in Opera 11.

Timo Huovinen said...

@Ingo I will check it out and post fixes/updates

Timo Huovinen said...

Sorry for the problem Ingo, it was caused by template updating, I have isolated the demo CSS, now it works again.

Anonymous said...

Thanks a lot for your work!

I don't find a solution to transform another example of your menu in multi level.

http://sharamiz.nuxit.net/menu/menu-3.htm

The difficulty is to keep a flexible width on the main links. The rest can be fixe ;--)

Again, thanks a lot for your help !

Timo Huovinen said...

@Anonymous at first glance: you need to make the inner levels slightly smaller in width! this stops them from cascading and opening any subsequent levels.

Post a Comment