How To Create A Dropdown Navigation Menu In Html
CSS is getting increasingly powerful, and with features like CSS grid and custom properties (also known as CSS variables), we're seeing some really creative solutions emerging. Some of those solutions focus around not only making the web prettier, but making it more accessible, and making styling accessible experiences better. I'm definitely here for it!
A common UI pattern that we see on the web are dropdown menus. They're used to display related information in pieces, without overwhelming the user with buttons, text, and options. Somewhere that we see these a lot is inside of headers or navigation areas on websites.
Let's see if we can make one of these menus with CSS alone. We'll create a list of links within a nav component like so:
<nav role="navigation"> <ul> <li><a href="#">One</a></li> <li><a href="#">Two</a></li> <li><a href="#">Three</a></li> </ul> </nav>
Now, say we want a sub-menu dropdown on the second navigation item. We can do the same thing there and include a list of links within that list item:
<nav role="navigation"> <ul> <li><a href="#">One</a></li> <li><a href="#">Two</a> <ul class="dropdown"> <li><a href="#">Sub-1</a></li> <li><a href="#">Sub-2</a></li> <li><a href="#">Sub-3</a></li> </ul> </li> <li><a href="#">Three</a></li> </ul> </nav>
We now have our two-tiered navigation system. In order to have the content hidden and displayed when we want it to be visible, we'll need to apply some CSS. All style properties have been removed from the following example for clarity on interaction:
li { display: block; transition-duration: 0.5s; } li:hover { cursor: pointer; } ul li ul { visibility: hidden; opacity: 0; position: absolute; transition: all 0.5s ease; margin-top: 1rem; left: 0; display: none; } ul li:hover > ul, ul li ul:hover { visibility: visible; opacity: 1; display: block; } ul li ul li { clear: both; width: 100%; }
Now, the submenu dropdown is hidden, but will be exposed and become visible when we hover over its correlating parent in the navigation bar. By styling ul li ul
, we have access to that submenu, and by styling ul li ul li
, we have access to the individual list items within it.
The Problem
This is starting to look like what we want, but we're still far from finished at this point. Web accessibility is a core part of your product's development, and right now would be the perfect opportunity to bring this up. Adding role="navigation"
is a good start, but in order for a navigation bar to be accessible, one should be able to tab through it (and focus on the proper item in a sensible order), and also have a screen reader accurately read out loud what is being focused on.
You can hover over any of the list items and clearly see what is being hovered over, but this isn't true for tab navigation. Go ahead and try to tab through the example above. You lose track of where the focus is visually As you tab to Two in the main menu, you'll see a focus indicator ring, but when you tab to the next item (one of its submenu items), that focus disappears.
Now, it's important to note that theoretically you are focused on this other item, and that a screen reader would be able to parse that, reading Sub-One, but keyboard users will not be able to see what's going on and will lose track.
The reason this happens is because, while we're styling the hover of the parent element, as soon as we transition focus from the parent to one of the list items within that parent, we lose that styling. This makes sense from a CSS standpoint, but it's not what we want.
Luckily, there is a new CSS pseudo class that will give us exactly what we want in this case, and it's called :focus-within
.
The Solution: :focus-within
The :focus-within
pseudo selector is a part of the CSS Selectors Level 4 Spec and tells the browser to apply a style to a parent when any of its children are in focus. So in our case, this means that we can tab to Sub-One and apply a :focus-within
style along with the :hover
style of the parent and see exactly where we are in the navigation dropdown. In our case it would be ul li:focus-within > ul
:
ul li:hover > ul, ul li:focus-within > ul, ul li ul:hover { visibility: visible; opacity: 1; display: block; }
Sweet! It works!
Quick detour! If you're only supporting modern browsers, the CSS we've seen so far is fine. But you should know that when any browser doesn't understand part of a selector, it throws the entire selector out. So if you want to support IE 11, you can't mix in the :focus-within
part.
/* This compound selector will still work in IE 11 because :focus-within isn't mixed in */ ul li:hover > ul, ul li ul:hover, ul li ul:focus { visibility: visible; opacity: 1; display: block; } /* IE 11 won't get this, but at least the top-level menus will work */ ul li:focus-within > ul { visibility: visible; opacity: 1; display: block; }
Now, when we tab to the second item, our submenu pops up, and as we tab through the submenu, the visibility remains! Now, we can append our code to include :focus
states alongside :hover
to give keyboard users the same experience as our mouse users.
In most cases, such as on direct links, we usually can just write something like:
a:hover, a:focus { ... }
But in this case, since we're applying hover styles based on the parent li
, we can again utilize :focus-within
to get the same look at feel when tabbing through. This is because we can't actually focus on the li
(unless we add a tabindex="0"
). We're actually focusing on the link (a
) within it. :focus-within
allows us to still apply styles to the parent li
when focusing on the link (pretty darn cool!):
li:hover, li:focus-within { ... }
At this point, since we are applying a focus style, we can do something that's typically not recommended (remove the styling of that blue outline focus ring). We can do this by:
li:focus-within a { outline: none; }
The above code specifies that when we focus within list items via the link (a
), do not apply an outline to the link item (a
). It's pretty safe to write it this way, because we're exclusively styling the hover state, and with browsers that do not support :focus-within
, the link will still get a focus ring. Now our menu looks like this:
What About ARIA?
If you're familiar with accessibility, you may have heard of ARIA labels and states. You can use these to your advantage to also create these types of dropdowns with built-in accessibility at the same time! You can find an excellent example here by Heydon Pickering. When including ARIA markup, your code would look a little more like this:
<nav role="navigation"> <ul> <li><a href="#">One</a></li> <li><a href="#" aria-haspopup="true">Two</a> <ul class="dropdown" aria-label="submenu"> <li><a href="#">Sub-1</a></li> <li><a href="#">Sub-2</a></li> <li><a href="#">Sub-3</a></li> </ul> </li> <li><a href="#">Three</a></li> </ul> </nav>
You're adding aria-haspopup="true"
to the parent of the dropdown menu to indicate an alternative state, and including aria-label="submenu"
on the actual dropdown menu itself (in this case our list with class="dropdown"
.
These properties themselves will give you the functionality you need to show the dropdown menu, but the downside is that they only work with JavaScript enabled.
Browser Support Caveat
Speaking of caveats, let's talk about browser support. While :focus-within
does have pretty good browser support, it's important to note that Internet Explorer and Edge are not supported, so your users on those platforms will not be able to see the navigation.
Desktop
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
60 | 52 | No | 79 | 10.1 |
Mobile / Tablet
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
96 | 94 | 96 | 10.3 |
The ultimate solution here would be to use both ARIA markup and CSS :focus-within
to ensure a solid dropdown experience for your users.
If you want to be able to use this feature in the future, please upvote it on Edge User Voice! And upvote :focus-ring
while you're at it, so that we'll be able to style that focus ring and create a beautiful interactive web experience for all 😀
More on :focus-within
and A11Y
- Scott O'Hara wrote about
:focus-within
, highlighting demos like highlighted<table>
rows and dropdown menus - Kushagra Gour on creating a focus-trapped modal
- Eric Bailey on focus styles in general
- Chris on keeping a parent element visible when child is focused
- All articles on CSS-Tricks related to
:focus-within
How To Create A Dropdown Navigation Menu In Html
Source: https://css-tricks.com/solved-with-css-dropdown-menus/
Posted by: eastmansainest1939.blogspot.com
0 Response to "How To Create A Dropdown Navigation Menu In Html"
Post a Comment