When a webpage has more links than the designer wants to make visible, a common approach is to use a drop-down menu. You'll see an example at the top of this page, but I'm sure you're already familiar with them. While there are many ways to create drop-down menus, we will just discuss one of them.
Unlike many drop-down menus, however, we are going to require the
user to click on the menu in order to reveal the hidden links. This is
because the action of hovering over
a menu item, which works fine
with computer mice, doesn't work so well with touch-screen devices. By
using only the click event, our approach will work for both
mice and fingertips.
Here's a link to a page with the final drop-down menu that we will build. It is fully functional, mobile-friendly, and the CSS is comprehensible.
Use view source
on that page to see exactly how we did it.
display: inline-block
for the top-level
menu items (LI). This is similar to floating, in that the LI
elements are laid out horizontally, but we don't have trouble with
non-floated stuff coming up next to them and they contribute to the
height and widths of their parent. See
has_submenu
; we can use that class with
jQuery to add the click handlers.
$(this)
to get the element that was clicked
on.
.find()
method to find descendants of
the clicked element.
event.StopPropagation()
to keep a click on a top-level menu from bubbling up to the
document and causing the sub-menu to be closed.
Let's start with a set of menus without any CSS or JS at all:
Now, let's add the CSS to make them look pretty. You're welcome to look at the CSS, but we basically just use simple stuff like color, margin, padding, width, text-decoration:none, list-style-type:none, text-align and border. The more complex CSS is:
position:relative
on the top-level menu
items, so that the sub-menus are positioned relative to the
top-level item they belong to
position:absolute
to position the
sub-menus relative to their parents.
For purposes of exposition, we omitted
the display:none
on the sub-menus and made the parents
wider so that all the sub-menus could be displayed without
overlapping.
Now, we'll add a simple click-handler that just toggles the sub-menu. We'll add it by code like this:
function toggleSubmenu_v1() { $(this).find("ul").toggle(); } $(".has_submenu").click(toggleSubmenu_v1);
You could use this kind of interface, but it's not what people expect, because it's possible to open several menus at once. (Try it!) Usually, if you click on a heading, say "News", to open it, and then you on another heading, say "CS110", you expect the "News" submenu to close. We'll achieve this by adding a click handler to the document that closes all the submenus. Like this:
function closeAll() { $(".has_submenu ul").hide(); } $(document).click(closeAll);
However, that has a hidden trap, which is that if we click on
"News," that also counts as a click on the document. That
is, the click event bubbles
up the document from
child to parent until it reaches the very top (which is
the document
selector we saw above). What we want to do
is stop the bubbling or propagation of this event.
To do that, we add an argument to the click handler for top-level
menu items. The argument is typically called something
like event
or evt
. That argument will be
given a value by the browser when it invokes the click handler. The
value is an object that includes a lot of information about
the event. The event object also has a method
called stopPropagation
, which is exactly the tool we
need. So here's our new code:
function toggleSubmenu_v2(event) { event.stopPropagation(); $(this).find("ul").toggle(); } $(".has_submenu").click(toggleSubmenu_v2);
Here's the new menu:
We were inspired by this which we based on this wonderfully
written tutorial by Iggy
on
a how
to create a pure CSS Drop-down Menu. Unfortunately, that tutorial
uses :hover, which is great of desktop applications where a mouse can
hover over a menu item to reveal a submenu, but that doesn't work with
touch-screen applications, as most mobile devices are. Since we want to
write pages that are usable with touch-screens, we ultimately had to
abandon Iggy's approach. Still, hat's off to it.