Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Pure CSS Menus

0.00/5 (No votes)
19 Dec 2003 1  
Dynamic Dropdown Menus without JavaScript on IE.

Introduction

Have you ever heard that it is not possible to create pure CSS dynamic menus for IE? Am sure you had. Do you believe it? Better don't...

Purpose of this article

The purpose of the project - to build dropdown menus using only CSS that work on IE. Starting with this I extended the code to allow it work on some other well-known browsers.

The purpose of the article - more or less educational and gives main overview of a some "hidden" and rearly unused, browser features. As well as showing some tricks for those who are curious. In addition it can be used by (un)skilled developers to get some ideas (code) for their projects.

Reader's skill requirements

Actually I was thinking whether to mark this as an "Advanced". But I am sure even low skilled people should understand it well. So, you will need basic knowledge of CSS and HTML to read it. There are some articles in codeproject.com that will explain enough to catch this one.

What is different from the other's CSS menus?

I've been searching for long time the web for CSS menus and didn't find pure CSS solution that works on IE. Sure, I found some interesting ideas on different sites. They lead me to this one. It is not perfect, and the code is not clean, but I do not have enough time to make all the thinks right (even to check the grammar). The most interesting alternate solution I have found (uses some JavaScript) is based on adding the hover pseudo-class to the LI element. Never thought it is possible...However, I never thought that no script dropdown menus are possible on IE at all...

The main difference between my CSS menus and the other ones is that my work on IE. All of the solutions I found use LI as main element for the :hover pseudo-class, but Microsoft decided to attach it only to the A element. Most of the sites note that their menu will work only on Opera 7.x or Mozilla. But these browsers are used by less than 5% of the people! The beauty of the pure CSS menus cannot be seen on the most popular browser? Not anymore.

So lets start..

What is a CSS menu?

Ok, move your mouse over these two words...

What is a pure CSS menu?

This is a dynamic menu that doesn't use scripts (e.g. JavaScript), but uses only CSS styling and some html.

Incredible?

Let's see the code:
<STYLE type=text/css id="default" title="default" name="default">

*::-moz-any-link br,*:-moz-any-link br { 
/*a workarround for mozilla*/
display:none;
}
div#menu * {
  cursor: pointer; /*because IE displays the text cursor 
if the link is inactive*/
}
.disabled {
   color: red !important;
   background: none !important;
}
div#menu {
   background: #F5F5DC;
   font: 10px Verdana, sans-serif;
   height: 15px;
   white-space: nowrap;
   width: 100%;
}

div#menu .a {
   background: #F5F5DC;
   border: 1px solid #F5F5DC;
   color: #000000;
   text-decoration: none;
}

div#menu .a table {
   display: block;
   font: 10px Verdana, sans-serif;
   white-space: nowrap;
}

div#menu table, div#menu table a {
   display: none;
}

div#menu .a:hover, div#menu div.menuitem:hover {
   background: #7DA6EE;
   border: 1px solid #000080;
   color: #0000FF;
   margin-right:-1px; /*resolves a problem with Opera 
not displaying the right border*/
}

div#menu .a:hover table, div#menu div.menuitem:hover table{
   background: #FFFFFF;
   border: 1px solid #708090;
   display: block;
   position: absolute;
   white-space: nowrap;
}

div#menu .a:hover table a, div#menu div.menuitem:hover table a {
   border-left: 10px solid #708090;
   border-right: 1px solid white; /*resolves a jump problem*/
   color: #000000;
   display: block;
   padding: 1px 12px;
   text-decoration: none;
   white-space: nowrap;
   z-index: 1000;
   
}

div#menu .a:hover table a:hover, div#menu div.menuitem:hover table a:hover {
   background: #7DA6EE;
   border: 1px solid #000000;
   border-left: 10px solid #000000;
   color: #000000;
   display: block;
   padding: 0px 12px;
   text-decoration: none;
   z-index: 1000;
}

td {
   border-width: 0px;
   padding: 0px 0px 0px 0px;
}
.menuitem {
   float: left;
   margin: 1px 1px 1px 1px;
   padding: 1px 1px 1px 1px;
}

.menuitem * {
   padding: 0px 0px 0px 0px;
}
#other {
  height: auto;visibility: visible;
}
#moz{
  height: 1px;visibility: hidden;
}
#moz::-moz-cell-content{
  height: auto; visibility: visible;
}
#other::-moz-cell-content{
  height: 1px; visibility: hidden;
}
#holder {
  width: 100%;
}

</STYLE>

<TABLE id=holder>
    <TR>
        <TD id="other">
            <DIV id="menu">
                <DIV class="menuitem">
                    <a class="a" href='#'>File<BR>
                    <TABLE>
                        <TR>
                            <TD><a href=#2>Open ili op dulgo</A></TD>
                        </TR>
                        <TR>
                            <TD><a href=#3>Save</A></TD>
                        </TR>
                        <TR>
                            <TD><a href=#4>Close</A></TD>
                        </TR>
                    </TABLE>
                </DIV>
                <DIV class="menuitem">
                    <A class="a" href="#11">Help<BR>
                    <TABLE>
                        <TR>
                            <TD><a class="disabled">..</A></TD>
                        </TR>
                        <TR>
                            <TD><a href=#13>Index</A></TD>
                        </TR>
                        <TR>
                            <TD><a href="#14">About</A></TD>
                        </TR>
                    </TABLE>
                </DIV>
            </DIV>
        </TD>
    </TR>
    <TR>
        <TD id="moz"> Mozilla specific menu!
            <DIV id="menu">
                <DIV class="menuitem">
                    <a class="a" href='#'>Filezilla</A>
                    <TABLE>
                        <TR>
                            <TD><a href=#2>Open</A></TD>
                        </TR>
                        <TR>
                            <TD><a href=#3>Save</A></TD>
                        </TR>
                        <TR>
                            <TD><a href=#4>Close</A></TD>
                        </TR>
                    </TABLE>
                    </a>
                </DIV>
                <DIV class="menuitem">
                    <A class="a" href="#11">Helpzilla</A>
                    <TABLE>
                        <TR>
                            <TD><a class="disabled">..</A></TD>
                        </TR>
                        <TR>
                            <TD><a href=#13>Index</A></TD>
                        </TR>
                        <TR>
                            <TD><a href="#14">About</A></TD>
                        </TR>
                    </TABLE>
                    </A>
                </DIV>
            </DIV>
        </TD>
    </TR>
</TABLE><BR>

What is going on here?

I won't teach you how to use CSS, this is not the point of my article. Therefore I will start from the core of this stylesheet - the ':hover' pseudo-class. Yes it is a class! It means: a selector can inherit another selector that includes ':hover'. In our case 'A:hover TABLE' selects '<TABLE> in <A> hovered by the mouse'. Further part of the trick is that we have a table with its display property set to none (meaning invisible). This table is between an anchor tags (<A>,</A>). Microsoft said that this may cause strange behavior on IE, but I didn't noticed any...

Why we use a table? This is because it will successfuly detach the nested anchors we want to use from the main anchor. Actually it doesn't on Mozilla 0.7 and I still havn't found a no JavaScript solution. Direct nesting of anchors is not allowed by Microsoft, therefore the table is a workaround (or a hack) for IE. As I know only a table does the work.

So, what do we have here? 2 tables with anchors inside an anchor.

        <A class="a" href="#11" >Help<BR>
        <TABLE cellpadding="0" cellspacing="0" border="0">
            <TR>
                <TD><a href="#12">Howto</A></TD>
            </TR>
            <TR>
                <TD><a href="#13">Index</A></TD>
            </TR>
            <TR>
                <TD><a href="#14">About</A></TD>
            </TR>
        </TABLE></A>

They are hidden.

div#menu .a table {
   display: none;
   z-index:-1;
}

The browser shows the contents of the anchor when the mouse moves over it and applies the style:

  • For the text of link:
div#menu .a:hover {
   background: #7DA6EE;
   border: 1px solid black;
   color: black;z-index:0;
}
  • For the dropdown table that we use for sub menus: The key to all - shows the dropdown.
div#menu .a:hover table{
   background: White;
   display: block;
   position: absolute;
   width: 125px;z-index: 0;
   border: 1px solid #708090;

}
  • For the links inside the sub menus:
div#menu .a:hover table a {
   display: block;
   color: Black;
   text-decoration: none;
   padding: 1px 12px;z-index:1000;
}

If we hover one of the links into the submenu the browser applies:

  • For the links inside the sub menus:
div#menu .a:hover table a:hover {
   display: block;
   background: #7DA6EE;
   color: black;
   text-decoration: none;
   padding: 0px 11px;
   border: 1px solid black;z-index:1000;
   visibility: visible;
}
  • The style of the links in the dropdown.
div#menu .a:hover table a {
   display: block;
   color: Black;
   text-decoration: none;
   padding: 1px 12px;z-index:1000;
}

May be you did noticed some 'z-index' properties. They are workaround for some problems I found while testing the menu.

Improvements

You can extend the whole thingy to have sublevels in the dropdown menus. Just insert another div '.menuitem'(with its content and the same structure) instead of some link into the parent's table. Now you have sublevel into your menu. You will have to remove the <BR> tag to let the menu show aside. In addition you have to create number of copies of the classes .menuitem and .a with the same properties but with different name for every sublevel. Seem lots of work, but you can simply add their selectors to the appropriate section in the style sheet

A complete description how to do it I will add another time. Of course this is pure CSS and you can customize everything. The possibilities are infinite - your imagination is not...

Style switching (Skins)

If you wish to add different skins for the same menu that the user can switch, you have to add them as different STYLE sheets and name them with id='some_name' (for IE) and name='some_name' (for others). For not applying both styles you have to disable all except the default one by adding "disabled" into the style defining tag (no matter whether you link it or use the inline syntax). Mozilla and Opera allow switching of the named styles from inside the browser. Usually these browsers do not apply all styles that are defined with name="..." and DO ignore id="...". Also they threat name='default' as default stylesheet and name='alternate' as alternative stylesheets. You can define the name of the style that the user will see by the title="..." property. As an example: the live demo on this page include these definitions:

<STYLE type=text/css id="alternate" title="Blue" name="alternate" disabled>
...<STYLE>

<STYLE type=text/css id="default" title="Default" name="default">
...<STYLE>

Note the naming conventions and order, which I strongly recommend you to follow.

IE doesn't have built-in switching of css styles so we have to implement one (no way we have to use some JavaScript):

Click one to choose and go up to see the changes:


Which has this simple code:
<ul>
  <li onclick="document.styleSheets('default').disabled=false; 
          document.styleSheets('alternate').disabled=true;">
  <a>Default</a>
  </li>
  <li onclick="document.styleSheets('alternate').disabled=false; 
            document.styleSheets('default').disabled=true;">
  <a>Blue</a>
  </li>
  <li onclick="document.styleSheets('alternate').disabled=true; 
          document.styleSheets('default').disabled=true;">
  <a>No Stylesheet</a>
  </li>
</ul>

Warning! This is just a brief overview! Reloading the page will reload the default state of the stylesheets! Therefore for a real purpose you have to use cookies or serverside scripts to keep the users choice, which is not the point of the article. In adittion the above code works only on IE.

In conclusion

I definitely propose using a CSS menu in your website (web application), because most of the problems and bugs of the JavaScript menus are escaped. Such problems are usually caused by strange firing (or not firing) of mouse events by IE. Furthermore some browsers are able to switch off its Script support and for sure doesn't support M$'s JavaScript!

If the browser does not support CSS it will still show all of the links (you can try the above style switcher to turn off the styles). It will show the Mozilla menu too.

The 'Mozilla problem' - the links inside the submenus don't work. It is not possible to open into the same page (but work with shift+click). See 'bugs'.

I hope all that was helpful. Have a nice day.

Updates

  1. The problem with the <br> on Mozilla is resolved by adding this code into the stylesheet:
    a br,a:hover br { /*workarround for mozilla*/
     float:left;width:0px;padding:0px 0px 0px 0px;}
    

    The main code is corrected too
  2. The main links were separated, and the pixel-jump bug corrected.
  3. Added support of disabled items.
  4. Added Mozilla specific(alternate) menu, point 1. is no longer necessary. See 'bugs'.
  5. 21st dec: Added the skin section (added an alternate style not included in the visible code)
  6. 21st dec: Almost completed the Mozilla's section (have some style bugs, but works)
  7. 21st dec: Added/rewritten some parts of the article
  8. 21st dec: Added the source of the live demo for download as .zip file.

Known bugs

By default the links on the submenus don't work on Mozilla. But I did found some kind of solution for this. It is based on inserting a specific menu for this browser again without any scripting. Inspect the parts of the code where is mentioned Mozilla (or 'moz'). You will see that the HTML part doesn't have nesting of anchors (the last </a> is moved where it should stay usually). In the CSS part I use some undocumented selectors - pure Mozilla specific, and added :hover selector for the divs which is supported by Mozilla. It still have some minor style misbehavior.

I have a comment (by Nick Young) that it won't work on Netscape. I am sure the problem is the same as Mozilla. Have to search some more info about it. The eventual fix will require minor changes because the alternate code should work OK on Netscape.

Notes:

  • The code extractions may slightly differ from the main code. There are no significant changes that require updating them too.
  • The page is tested by me on Internet Explorer 5, 5.5, 6, Opera7.23 and Mozilla 0.71. I think it will work on some previous versions of these browsers.
    • P.S. Please, do not post me links to sites for CSS Menus, I've seen all(!) that Google found. None of them involve JavaScript menus for IE!
    • P.P.S. Don't forget to vote :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here