Bootstrap mega menu

My selfie

James Turner,

Tags: Bootstrap HTML JavaScript

For everything you need to know about what's good on TV and in film, go no further than Rotten Tomatoes, the review aggregation site. Its website is responsive, with customised styles layered on top of Bootstrap. The content on Rotten Tomatoes (RT) has more in common with a sports league table than a typical review site. The landing page packs in both quantitative data (percentage of positive reviews and the Tomatometer™) and qualitative information (a summary of what critics are saying) for hundreds of the latest TV programmes and films. In the next few posts, I'd like to look at how the content is laid out to create a fun experience, starting with its implementation of the Bootstrap dropdown menu.

The dropdown mega menu

On a desktop, the main navigation bar is very simple, with a search input and four key menu items. But behind each menu item lies a secret garden of links, headings and images (Figure 1), which presumably get updated on a constant basis as more reviews are aggregated.

When the mouse hovers over a menu item, a submenu containing dozens of links and an image or two appears.
Figure 1: When the mouse hovers over the menu item, the dropdown menu appears, layered above the content.

Markup demystified

The markup for the dropdown menu as a whole looks pretty complicated, with lots of nested divs, uls and lis. When you break it down, though, it's not too bad. At the top, we have a ul with the Bootstrap class of navbar-nav. Inside this are four li elements, one for each of the main menu items (‘Movies and DVDs’, ‘TV’, ‘News’ and ‘Tickets and showtimes’). Three of the four have the Bootstrap class of dropdown.

<ul class="navbar-nav (among others)">
  <li class="dropdown etc"><!-- Movies &amp; DVDs --></li>
  <li class="dropdown etc"><!-- TV --></li>
  <li class="dropdown etc"><!-- News --></li>
  <li><!-- Tickets &amp; showtimes --></li>
</ul>

Each li.dropdown has three or four columns of links and images. These are marked up with the Bootstrap row and col-*-* classes. For example, here's the structure of the ‘TV’ menu:

<li class="dropdown dropdown-toggle etc">
  <a id="tvMenu" class="h2" href="/top-tv/"> TV<span class="fontelloIcon icon-down-dir"/></a>
  <div id="tvMenuDropdown" class="dropdown-menu" role="menu" aria-labelledby="tvMenu">
    <div class="row">
      <div class="col-xs-7">
        ...
      </div><!-- col -->
      <div class="col-xs-7">
        ...
      </div><!-- col -->
      <div class="col-xs-5">
        ...
      </div><!-- col -->
      <div class="col-xs-5">
        ...
      </div><!-- col -->
    </div><!-- row -->
  </div><!-- dropdown-menu -->
</li><!-- dropdown -->

There are a few observations to make here. Firstly, the span tag after ‘TV’ is invalid. According to w3.org's specification of span, the closing tag isn't omissible.

Secondly, it doesn't use Bootstrap's default Glyphicon Halflings font for the little down-arrows after each top-level menu item. Instead, it uses Fontello. I'd be interested to find out why. I suspect it's because Fontello allows you to download and use individual glyphs, rather than having to download a whole font file just so that you can use one or two characters. This means that the website is downloading fewer unnecessary assets.

Another observation is that the default Bootstrap grid has twelve columns, but in RT's dropdown menu the columns add up to 24. The styles for this don't seem to come from the custom style sheet, so I guess they edited the Bootstrap base code directly in order to squeeze in 24 columns.

A lot of the content inside the mega menus on Rotten Tomatoes is dynamic. Where this is the case, the static web page simply contains a loader GIF, and the latest content is presumably swapped in once it's been fetched from a database. One column has ‘hard-coded’ content, I guess so that readers have something to look at while the rest of the content is loading. I wonder why this dynamic data isn't fetched from a database before the page is served, i.e. using a server-side language like PHP. Perhaps it would just take too long, or even break the server with a high-traffic site like Rotten Tomatoes. Adding dynamic content in this way would be a great idea for a future post, but I'll just stick to the menu for now.

Anyway, here's my attempt at creating my own mega menu on Codepen.

Making mega menus responsive

By default, Bootstrap's .navbar elements only appear above 768px. For smaller screen widths, it's good practice to include a .navbar-header element with a toggle button that opens up the navigation, as shown on the Bootstrap components page. The menu items in the navbar appear in the same order as at desktop width, and dropdown menus are still togglable.

Because the mega menus on Rotten Tomatoes are so stuffed with content, the site handles things a little differently to the default Bootstrap set-up. Instead of using the same menu for desktop and mobile, RT has one menu for mobile and another for desktop, and hides one or the other according to screen size. The desktop and mobile menus don't even have the same links; for small-screen users, the content that is prioritised in the main navigation is social media, film (including buying tickets) and signing up for the Rotten Tomatoes newsletter. The mega menu is nowhere in sight. I would imagine that the Rotten Tomatoes design team researched how the features that users were accessing varied by device, and designed the navigation accordingly.

Layers of enhancement

In Adaptive Web Design, 2nd Edition (2015), Aaron Gustafson talks about layers of enhancement, rather like a pyramid. At the base of the pyramid, we have content. Next is markup (HTML). Then comes styling (CSS). Finally, there's behaviour (JavaScript). Each level should be designed so that if there's some kind of error, the layer below acts as a safety net, and the user can still do the task she came to do.

So what happens to Rotten Tomatoes' mega menus if different layers fail? Is the content still accessible? At the top of the pyramid is JavaScript, and Bootstrap's dropdown menus are heavily JS-dependent. As well as jQuery, they also use Bootstrap's own JS library. If either or both of these fail to download and execute, the dropdown menus will not open, but the user will still be able to interact with the top-level links going across the .navbar. There doesn't seem to be a way around this; that's just how Bootstrap works.

One way to deal with this might be to ensure that if there's a link to a page in the dropdown menu, then that content can be accessed via another route, such as a link in the main content or the site search. Is this the case with Rotten Tomatoes? Let's say I want to find out what it has to say about TV shows currently streaming on Netflix. I can't use the ‘Netflix Streaming’ link in the ‘Movies & DVDs’ dropdown menu because jQuery isn't working. Unfortunately, there doesn't seem to be any other way to reach that particular page, and when I search for ‘Netflix Streaming’ I just get a ‘Sorry, no results…’ message. The lesson, then, is to make sure that no critical content is buried in these fragile dropdown menus.

Keyboard accessibility

As well as clicking and tapping, many users also interact with websites using a keyboard. The A11y Project recommends a five-second test to check keyboard accessibility: try to navigate the site using just Tab, Enter and the four arrow keys.

Out of the box, Bootstrap's dropdown menus are keyboard accessible. I tried navigating my mega menu example, and it works just fine. However, Rotten Tomatoes' menu isn't fully keyboard accessible. The problem is that you can tab through the top-level links, but the down arrow key doesn't open the menu—instead, it scrolls down the screen. (At this point, I can't work out why, but I'll update this post if I find out.) It's a shame that Rotten Tomatoes' developers have made the Bootstrap dropdown menu less accessible.

For a more in-depth discussion of accessibility and dropdown menus, see Accessible Dropdown Menus Revisited, by Terrill Thompson (2013).

25/04/2016: I came across this example of an accessible mega dropdown menu. It is a jQuery plug-in with good documentation on how to include it in your project.

Conclusion

The content on Rotten Tomatoes has a much more quantitative flavour than most websites, so I can see why they tried to stuff their menus with links. Unfortunately, they've somehow made Bootstrap's dropdown menu inaccessible to keyboard users, and the menu contains links that can't be reached if one of several JS scripts fail. The argument against accessibility and progressive enhancement is always, “well, it's only 2% of users that are affected”. Think, though. If a restaurant, or a car manufacturer, or a hospital, had a fault rate of 2%, how long would it stay in business? Maybe it's not the end of the world for Rotten Tomatoes. There's plenty of content on the landing page to keep marginalised visitors amused. That is, if they hang around long enough to get to it.

On the positive side, it has been interesting for me to see how a website in the field has adapted Bootstrap's dropdown menu to its own ends. I would never have thought of adding several columns of links to a dropdown menu. Neither would I have used anything other than the sacred 12-column grid, or a different icon font. Perhaps CSS frameworks aren't so bad, after all?

Further reading

In addition to the above links, here are some more articles related to Bootstrap and its dropdown menu:

Skip to navigation