{"id":150992,"date":"2013-09-23T10:09:22","date_gmt":"2013-09-23T17:09:22","guid":{"rendered":"http:\/\/css-tricks.com\/?p=150992"},"modified":"2017-04-13T16:28:57","modified_gmt":"2017-04-13T23:28:57","slug":"targetting-menu-elements-submenus-navigation-bar","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/targetting-menu-elements-submenus-navigation-bar\/","title":{"rendered":"Targeting Menu Elements with Submenus in a Navigation Bar"},"content":{"rendered":"

The following is a guest post by Ray Messina<\/a>. Ray was interested in sharing this technique as a way to pay forward things he’s learned from this site in the past, which is awesome. You might be aware of the jQuery .has<\/code> method, which allows you to select an element if it has any of another selector as a descendant. There is sadly no such selector in CSS yet. But if you know a little something about the HTML structure, you can use a combination of positional selectors to mimic it. Ray will explain.<\/em><\/p>\n

<\/p>\n

Recently, I was working on a dropdown navigation bar and wanted to differentiate the menu items which contained sub menus from those that didn’t. I wanted to be able to do this automatically, without relying on JavaScript or having to add classes to the markup. I just wanted it to work as if the item just knew<\/em> it had a sub menu or not.<\/p>\n

The Need for Navigational Hints<\/h3>\n

As you probably know, menus are lists of links and, as such, it is standard practice to mark them up as <ul><\/code>s. By extension, drop down menus are merely nested <ul><\/code>s. Dropdowns<\/em> are a common component of modern (and not so modern) web design. Using pure CSS, one can style the upper level of a navigation menu any which way, and hide the sub levels so that they are revealed only when the visitor hovers on the appropriate area.<\/p>\n

Many designers are satisfied with leaving as that. However, from a UX\/UI point of view, this is lacking as it leaves the user having to explore the entire menu to find which sections contain additional navigation links. This means visitors will either waste their time looking and get frustrated for doing so or miss areas of your site all together! That’s no good at all.<\/p>\n

The common way to address this issue, is to simply add a class to the <li><\/code>s that contain <ul><\/code>s (sub menus) so that we can style those items differently from those that do not contain sub navigation. Pretty simple, but also pretty tedious and not particularly graceful.<\/p>\n

Another way, assuming that upper level items are not<\/em> coded as links, is to use that difference in tags as leverage<\/em>. That is, create faux links<\/em>: style <span><\/code>s that’s are direct children of the <li><\/code> to indicate that there are more links that follow and, by contrast, style anchor tags as not having additional sub items. This is handy if your drop-down is simple and you can structure it specifically that way. It’s cleaner in that you don’t have to add “submenu” classes to your markup but, just as before, it still requires that you structure the content of your list manually or that your CMS can foretell which list items will contain other <ul><\/code>s as sub menus.<\/p>\n

Doing It Automatically!<\/h4>\n

I had come across other methods of automatically styling list items which contain other lists, but they employed absolute positioning and a pseudo element off the child <ul><\/code><\/em>. While clever, the CSS calculations can be tricky at times or the method may be entirely impossible to implement depending on what other techniques you have used to lay out your menu and\/or position your submenus, or the overall effect you desired to achieve.<\/p>\n

A better way<\/h4>\n

Ideally, it would be great if there was a CSS selector that would let us query if an element contained another kind of element as a direct child, something akin to jQuery’s .has()<\/code> method.<\/p>\n

We can can achieve nearly the same thing with li a:first-child:nth-last-child(x) { }<\/code>.<\/p>\n

The key is having an expected child count<\/strong> (HTML element planned parenthood?). Most likely it will be two elements: the anchor and the <ul><\/code>, though one can tweak this technique to work for any number or child elements, as long as you have a regular pattern.<\/p>\n

Here is a quick example. The markup is just your standard nested UL, but note that I have only used one class in the HTML<\/strong>, on the root <ul><\/code>. Test this out yourself, add any number of nested lists at any level!<\/p>\n

<\/figure>\n

Creating a Dropdown Demo<\/h3>\n

Let’s put this idea to the test!<\/p>\n

The HTML: Keep It Clean<\/h4>\n
<nav>\r\n  <ul class=\"nav\">\r\n    <li><a href=\"#\">About<\/a><\/li>\r\n    <li><a href=\"#\">Portfolio<\/a>\r\n      <ul>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n      <\/ul>\r\n    <\/li>\r\n    <li><a href=\"#\">Resume<\/a>\r\n      <ul>\r\n        <li><a href=\"#\">item a lonng submenu<\/a><\/li>\r\n        <li><a href=\"#\">item<\/a>\r\n          <ul>\r\n            <li><a href=\"#\">Ray<\/a><\/li>\r\n            <li><a href=\"#\">Veronica<\/a><\/li>\r\n            <li><a href=\"#\">Bushy<\/a><\/li>\r\n            <li><a href=\"#\">Havoc<\/a><\/li>\r\n          <\/ul>\r\n        <\/li>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n      <\/ul>\r\n    <\/li>\r\n    <li><a href=\"#\">Download<\/a><\/li>\r\n    <li><a href=\"#\">Rants<\/a>\r\n      <ul>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n        <li><a href=\"#\">item<\/a><\/li>\r\n      <\/ul>\r\n    <\/li>\r\n    <li><a href=\"#\">Contact<\/a><\/li>\r\n  <\/ul>\r\n<\/nav><\/code><\/pre>\n

The CSS<\/h4>\n

Some general styling to bring in the sexy: <\/p>\n

nav {    \r\n  display: block;\r\n  text-align: center;\r\n}\r\nnav ul {\r\n  margin: 0;\r\n  padding:0;\r\n  list-style: none;\r\n}\r\n.nav a {\r\n  display:block; \r\n  background: #111; \r\n  color: #fff; \r\n  text-decoration: none;\r\n  padding: 0.8em 1.8em;\r\n  text-transform: uppercase;\r\n  font-size: 80%;\r\n  letter-spacing: 2px;\r\n  text-shadow: 0 -1px 0 #000;\r\n  position: relative;\r\n}\r\n.nav{  \r\n  vertical-align: top; \r\n  display: inline-block;\r\n  box-shadow: \r\n    1px -1px -1px 1px #000, \r\n    -1px 1px -1px 1px #fff, \r\n    0 0 6px 3px #fff;\r\n  border-radius:6px;\r\n}\r\n.nav li {\r\n  position: relative;\r\n}\r\n.nav > li { \r\n  float: left; \r\n  border-bottom: 4px #aaa solid; \r\n  margin-right: 1px; \r\n} \r\n.nav > li > a { \r\n  margin-bottom: 1px;\r\n  box-shadow: inset 0 2em .33em -0.5em #555; \r\n}\r\n.nav > li:hover, \r\n.nav > li:hover > a { \r\n  border-bottom-color: orange;\r\n}\r\n.nav li:hover > a { \r\n  color:orange; \r\n}\r\n.nav > li:first-child { \r\n  border-radius: 4px 0 0 4px;\r\n} \r\n.nav > li:first-child > a { \r\n  border-radius: 4px 0 0 0;\r\n}\r\n.nav > li:last-child { \r\n  border-radius: 0 0 4px 0; \r\n  margin-right: 0;\r\n} \r\n.nav > li:last-child > a { \r\n  border-radius: 0 4px 0 0;\r\n}\r\n.nav li li a { \r\n  margin-top: 1px;\r\n}<\/code><\/pre>\n

Then the magic happens<\/strong>:<\/p>\n

.nav li a:first-child:nth-last-child(2):before { \r\n  content: \"\"; \r\n  position: absolute; \r\n  height: 0; \r\n  width: 0; \r\n  border: 5px solid transparent; \r\n  top: 50% ;\r\n  right:5px;  \r\n }<\/code><\/pre>\n

That’s essentially the active ingredient of this technique. For this example, I used the :before<\/code> pseudo element off the anchor element to draw the arrows. The pseudo element is not necessary<\/em> to the technique. I could have just as easily changed backgrounds on the anchor itself instead; you can make it do most anything you want once you have targeted the element.<\/p>\n

Finally, just to polish it off, some positioning and arrow styling CSS code.<\/p>\n

\/* submenu positioning*\/\r\n.nav ul {\r\n  position: absolute;\r\n  white-space: nowrap;\r\n  border-bottom: 5px solid  orange;\r\n  z-index: 1;\r\n  left: -99999em;\r\n}\r\n.nav > li:hover > ul {\r\n  left: auto;\r\n  margin-top: 5px;\r\n  min-width: 100%;\r\n}\r\n.nav > li li:hover > ul { \r\n  left: 100%;\r\n  margin-left: 1px;\r\n  top: -1px;\r\n}\r\n\/* arrow hover styling *\/\r\n.nav > li > a:first-child:nth-last-child(2):before { \r\n  border-top-color: #aaa; \r\n}\r\n.nav > li:hover > a:first-child:nth-last-child(2):before {\r\n  border: 5px solid transparent; \r\n  border-bottom-color: orange; \r\n  margin-top:-5px\r\n}\r\n.nav li li > a:first-child:nth-last-child(2):before {  \r\n  border-left-color: #aaa; \r\n  margin-top: -5px\r\n}\r\n.nav li li:hover > a:first-child:nth-last-child(2):before {\r\n  border: 5px solid transparent; \r\n  border-right-color: orange;\r\n  right: 10px; \r\n}<\/code><\/pre>\n

Here is the whole thing in action at CodePen:<\/p>\n

See the Pen Marking sub-menued items (sexy version)<\/a> by Ray Messina (@RayM<\/a>) on CodePen<\/a><\/div>\n

As you probably guessed, you could also use other selector\/selector combinations such as :only-child<\/code>, :first-child:last-child<\/code>, :first-child:not(:last-child)<\/code> and the like. But I have found that :nth-child(x):nth-last-child(x)<\/code> gives the most flexibility<\/strong> and serves as a built-in fallback (as it allows us to target the element directly, rather than by exclusion), and there is little cross browser support advantage gained by using the other selector\/selector combinations.<\/p>\n

That’s it. Simple, graceful and totally automatic; the way it ought to be. Support for this is almost universal, except for IE, which eats glue and only offers support in IE9+. At the time of writing, estimated global support for these selectors, as used, was roughly 87% which is not too bad. <\/p>\n","protected":false},"excerpt":{"rendered":"

The following is a guest post by Ray Messina. Ray was interested in sharing this technique as a way to pay forward things he’s learned from this site in the past, which is awesome. You might be aware of the jQuery .has method, which allows you to select an element if it has any of […]<\/p>\n","protected":false},"author":248413,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[4],"tags":[],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":270203,"url":"https:\/\/css-tricks.com\/solved-with-css-dropdown-menus\/","url_meta":{"origin":150992,"position":0},"title":"Solved with CSS! Dropdown Menus","date":"May 1, 2018","format":false,"excerpt":"A common UI pattern that we see on the web are dropdown menus. They\u2019re 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\u2019s see if we\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/04\/dropdown-menu-collage.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":333285,"url":"https:\/\/css-tricks.com\/i-saw-two-mega-menus-today\/","url_meta":{"origin":150992,"position":1},"title":"I Saw Two Mega Menus Today…","date":"February 2, 2021","format":false,"excerpt":"One was the footer of an (older) U.S. Government website. The other was the navigation for AWS services from the AWS Console.","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/01\/Screen-Shot-2021-01-20-at-10.50.52-AM.png?fit=1200%2C1097&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":19174,"url":"https:\/\/css-tricks.com\/off-canvas-menu-with-css-target\/","url_meta":{"origin":150992,"position":2},"title":"Off Canvas Menu with CSS :target","date":"November 7, 2012","format":false,"excerpt":"\"Off Canvas\" patterns are different ways to approach layout where content on the web isn't just laid out in a vertical column. For instance, navigation could be positioned hidden off the left edge of the \"canvas\" (visible browser window) and slid in on demand. Anthony Colangelo created jPanelMenu to do\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":276762,"url":"https:\/\/css-tricks.com\/one-invalid-pseudo-selector-equals-an-entire-ignored-selector\/","url_meta":{"origin":150992,"position":3},"title":"One Invalid Pseudo Selector Equals an Entire Ignored Selector","date":"October 5, 2018","format":false,"excerpt":"Perhaps you know this one: if any part of a selector is invalid, it invalidates the whole selector. For example: div, span::butt { background: red; } Even though div is a perfectly valid selector, span:butt is not, thus the entire selector is invalidated \u2014 neither divs nor span::butt elements on\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/09\/pseudo-selector-fail.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":334666,"url":"https:\/\/css-tricks.com\/how-we-improved-the-accessibility-of-our-single-page-app-menu\/","url_meta":{"origin":150992,"position":4},"title":"How We Improved the Accessibility of Our Single Page App Menu","date":"February 25, 2021","format":false,"excerpt":"I recently started working on a Progressive Web App (PWA) for a client with my team. We\u2019re using React with client-side routing via React Router, and one of the first elements that we made was the main menu. Menus are a key component of any site or app. That\u2019s really\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/menu-button.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":207389,"url":"https:\/\/css-tricks.com\/diy-priority-plus-nav\/","url_meta":{"origin":150992,"position":5},"title":"DIY Priority+ Navigation","date":"August 31, 2015","format":false,"excerpt":"We've written a bit about the Priority+ pattern here before. Here's a bunch of real world examples. I needed to use it recently. I found Gijs Rog\u00e9's priority-navigation. It's pretty nice: no dependencies, clean code, fairly configurable and designable. It's not particularly small though, and there is a good amount\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"featured_media_src_url":null,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/150992"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/248413"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=150992"}],"version-history":[{"count":7,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/150992\/revisions"}],"predecessor-version":[{"id":253682,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/150992\/revisions\/253682"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=150992"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=150992"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=150992"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}