Introduction
Yes - another "pure CSS menu" solution. This version has some nice features though:
- Supports both horizontal and vertical orientation of all menus and sub-menus
- Supports all combinations of orientation when moving from menu to sub-menu (that is, both horizontal and vertical sub-menus are nicely supported, regardless of whether the parent menu is horizontally or vertically oriented)
- Unlimited levels of submenus are supported, without the need for special classes (e.g. "
level-1-menu
", "level-2-menu
" at each level) - Uses classed
DIV
s instead of UL
/LI
or tables - this keeps the structure simple - I have fully documented the CSS so that it is easily customizable, and the structure of the HTML to build the menu is extremely simple.
Here's a sample of a menu built from this CSS/HTML that shows multiple levels and orientations:
Also contained in the sample code, but not shown above, is multiple joined levels of horizontal menus. To access that, navigate to [Item 1 -- Sub Item 1 -- Sub Sub Item 3] and you'll find them.
Using the Code
There are two main steps to use this code. The first is easy - just copy the CSS into a CSS file and link it, or just include it in a <style type='text/css'>...</style>
tag in your HTML file.
Here's the CSS that generated the above example... A fully-commented version of the CSS is included in the project demonstration file, so I'll only make a few comments.
First, most of the CSS that follows is relatively important, but some of it can be changed. I am assuming that the reader has the knowledge to generally know what is safe to change and what isn't. If you decide to customize, just make sure you make small changes, and then test those changes to make sure nothing major has broken. A few items that are a bit tricky - the background-color
should be specified on div.menu
, even if you want the menu to be transparent; otherwise, a nasty little Internet Explorer bug comes into play where the menu sometimes wants to disappear even though the mouse is still hovering over it. You can use rgba(0,0,0,0)
to get a transparent menu and yet it seems to eliminate the Internet Explorer bug, but both 'transparent
' and simply not setting background-color
seem to let the bug occur, although it is intermittent. Another little issue with Internet Explorer is that the sub-menu positioning is a bit off. If you adjust the margin settings for the sub-menus and then test in Internet Explorer and other browsers, then you should see what I'm referring to, especially if you put a border around the sub-menus.
div.menu {
display: none;
color: white;
background-color: rgba(0,0,0,1);
}
div.top {
display: inline-block;
}
div.top.hmb > div.item {
display: inline-block;
}
div.menu > div.item {
white-space: nowrap;
cursor: pointer;
padding: 5px 10px;
margin: 0;
border-top: 4px solid transparent;
}
div.menu > div.item:hover {
background-color: #262626;
border-top: 4px solid #009ac7;
}
div.hmb > div.item:hover > div.vmb {
position: absolute;
display: block;
margin-top: 5px;
margin-left: -10px;
}
div.hmb > div.item:hover > div.hmb {
position: absolute;
display: block;
margin-top: 5px;
}
div.vmb > div.item:hover > div.vmb {
position: absolute;
display: inline-block;
margin-left: 6px;
}
div.vmb > div.item:hover > div.hmb {
position: absolute;
display: inline-block;
margin-left: 6px;
}
div.item:hover > div.hmb > div.item {
display: inline-block;
}
div.menu > div.item > a {
color: inherit;
text-decoration: none;
}
The key to making these menus work are the CSS blocks above that describe the sub-menu inheritance. For each of the four combinations of transitions between horizontal and vertical menus, the two properties position
and display
control how the sub-menus will be displayed. In all cases, we specify "position: absolute
" so that the sub-menu is removed from the HTML flow, allowing the sub-menu to be displayed exactly where we want it. That CSS property setting is rather mundane, but the display
attribute is more interesting. For horizontal menus, we always want sub-menus to appear below the menu item, and for vertical menus, we always want sub-menus to appear to the right of the menu item. Because the containing DIV
appears immediately after the menu item text (refer to the HTML below), we specify "display: block
" for horizontal menu items to force the sub-menu to drop below the menu item text. Similarly, for vertical menu items, we specify "display: inline-block
" to allow the div
to be positioned next to the menu item text. In all cases, some minor adjustment of the exact positioning is warranted. Often, this is accomplished by using the top
/left
CSS properties with position: relative
. However, we cannot do that in this case because as mentioned, we need position: absolute
to ensure that the sub-menus don't affect the flow of the rest of the html on the page, and thus setting top
/left
would then move the DIV
to that exact location on the screen. Instead, we accomplish the position adjustment by setting the margin
CSS property of the sub-menu DIV
. Note that negative margins (a strange idea to many) are acceptable to move the DIV
in the opposite direction - that is, a positive margin-top
would move the DIV
down, but a negative margin-top
would move the DIV
up.
The second step is to build your HTML menu by using DIV
s and a few classes from the CSS above. The classes are:
menu
- This should be applied to any div
that contains menu items hmb
/ vmb
- Any <DIV class='menu'>
should also include either hmb
(horizontal menu bar) or vmb
(vertical menu bar). Choose just one. top
- This class just forces the menu to be displayed without the mouse hovering. As implied, this is typically used only at the "top" level of the menu item
- Apply this class to DIVs
that contain the individual menu items, regardless of whether the item contains a sub-menu or not
There are many ways to provide interaction with the menu. Some possibilities are by using <a>
tags, via onclick
JavaScript events on the DIV
s, or via javascript/jquery event subscription.
Here's the sample HTML that generated the example image:
<div class='menu top hmb'>
<div class='item'>
Item 1
<div class='menu vmb'>
<div class='item'>
Sub Item 1
<div class='menu hmb'>
<div class='item'>
Sub Sub Item 1
<div class='menu vmb'>
<div class='item'>
Level 4 - 1
<div class='menu vmb'>
<div class='item'>
Level 5 - 1
<div class='menu vmb'>
<div class='item'>Level 6 - 1</div>
<div class='item'>
Level 6 - 2
<div class='menu hmb'>
<div class='item'>Level 9 - 1</div>
<div class='item'>Level 9 - 2</div>
<div class='item'>Level 9 - 3</div>
</div>
</div>
<div class='item'>Level 6 - 3</div>
</div>
</div>
<div class='item'>Level 5 - 2</div>
<div class='item'>Level 5 - 2</div>
</div>
</div>
<div class='item'>Level 4 - 2</div>
<div class='item'>Level 4 - 3</div>
</div>
</div>
<div class='item'>Sub Sub Item 2</div>
<div class='item'>
Sub Sub Item 3
<div class='menu hmb'>
<div class='item'>Level 7 - 1</div>
<div class='item'>
Level 7 - 2
<div class='menu hmb'>
<div class='item'>Level 8 - 1</div>
<div class='item'>Level 8 - 2</div>
<div class='item'>Level 8 - 3</div>
</div>
</div>
<div class='item'>Level 7 - 3</div>
</div>
</div>
</div>
</div>
<div class='item'>Sub Item 2</div>
</div>
</div>
<div class='item'>
<a href='#'>Item 2</a>
</div>
<div class='item'>
Item 3
</div>
</div>
NOTE: Although this CSS/HTML menu does support "unlimited levels", I don't recommend going overboard. It's generally not considered good design to have menu structures that span more than 2-3 levels.
History
- 2016-01-19 - Initial publication