Horizontal “drop down” menus for site navigation are familiar to almost every web user, so they are a natural fit for sites that have many pages organized into seven or fewer categories.
Many web developers assume that creating a drop down menu requires JavaScript; the reality is that the menu system is merely a nested HTML list, just like those I have feature here in the past, with the presentation handled by CSS, no JavaScript required.
It should be noted that there are many, many CSS drop down menus available. The most well-regarded is “Suckerfish” code, originally developed on A List Apart. The system I am about to describe is an evolution of the ideas expressed in that article, with less vestigial code and fewer concessions to older browsers: thus, “Remora”.
First, the code. Since I am using nested lists, you should be careful to ensure that any new lists are contained insidean <li> element.
As I am currently residing in Auckland, I will make the drop down menu for a fictional boat-building website:
<nav>
<ul>
<li><a href="#">Yacht designs</a>
<ul>
<li><a href="#">Sloops</a>
<li><a href="#">Ketches</a>
<li><a href="#">Yawls</a>
<li><a href="#">Schooners</a>
</ul>
<li><a href=#>Small boat designs</a>
<ul>
<li><a href="#">Skiffs</a>
<li><a href="#">Tenders</a>
<li><a href="#">Dories</a>
<li><a href="#">Canoes</a>
<li><a href="#">Kayaks</a>
</ul>
<li><a href="#">Clippers</a>
</ul>
</nav>
Now the CSS. First, we will mini-reset both the list and links, removing all spacing, text decoration and bullets, while specifying a new font. At the same time, we’ll specify that each link in the list will always display on its own line; by doing so, we can also give links a set width
:
nav ul {
padding: 0;
margin: 0;
list-style-type: none;
font-size: 1.4rem;
}
nav ul a {
text-decoration: none;
color: #fff;
background: rgba(0,0,0,0.8);
font-family: Eurostile, Square 721, Arial, sans-serif;
display: block;
width: 10em;
padding: .4em;
transition: .3s;
}
This makes the entire navigation vertical, like the accordion menu example. We want the main <li>
elements to appear beside each other: we could try display: inline
, but that would remove any opportunity to provide them with a width
, in the event that we wanted to push the main menu items further apart. inline-block
and <flex>
have downsides too, in this case, so we’ll float the elements:
nav ul > li {
float: left;
position: relative;
}
Note the use of the immediate child combinator.
To create the “drop-down” effect we need to visually remove the submenu lists from the page. While there are many possibilities for achieving this, I'll position the submenus absolutely, and then give each submenu a value of 0 for opacity
. When the user hovers their mouse over the parent <li>,
opacity
is reset to 1
. A :focus
state is added to capture older mobile browsers:
nav ul li ul {
position: absolute;
opacity: 0;
transition: .4s;
}
nav ul li:hover ul {
opacity: 1;
}
You'll find one small issue: you can activate the submenus by moving your mouse over the area where the submenus lie on the screen, because they are still “there”, surrounded by their parent <li>
elements, just not visible. At the same time, the drop-down system won't work on older mobile browsers, which have no concept of “hover”. To fix both of these issues, the CSS is adjusted to:
nav ul li ul {
position: absolute;
opacity: 0;
transition: .4s;
pointer-events: none;
}
nav ul li:hover ul,
nav ul li:focus ul {
opacity: 1;
pointer-events: auto;
}
That’s it!. The system could be further improved by @media
queries for smaller screen sizes, but I'll leave that for other articles on this blog, and the CodePen repo linked below.
Photograph by Ilya Fedorov, licensed under Creative Commons.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/krdGh