Building Mega Menus with Flexbox

Share this article

Mega Menus with Flexbox
Mega Menus with Flexbox

As you are probably aware, Flexbox has recently gained momentum with increasing browser support. It allows developers to build complex user interfaces without dealing with unwanted CSS and JavaScript hacks.

Flexbox uses a linear layout model, which allows us to lay our content horizontally or vertically without involving calculations for spacing. The flex layout reacts responsively to the elements within the container, thus requiring fewer media queries.

In this article I will make use of this layout model to build a mega navigation menu and in the process you’ll see how simple it is to build and extend user interface components with flexbox.

I won’t discuss individual Flexbox properties in detail here, but instead the focus will be on the practical use of the features. For a basic introduction to Flexbox, please refer the following resources:

What Are We Building?

To get an idea of what I’ll be showing you how to build, take a look at the full-screen CodePen.

This tutorial is divided into three parts:

  1. Building the navigation bar: Using flexbox to build a simple navigation bar for our imaginary e-commerce platform
  2. Building a single drop-down section
  3. Limiting a single drop-down section to three columns

Building the Navigation Bar

The markup for the navigation bar is simple. I will handle everything with two classes (navbar and menu) for the sake of this demo. The CSS here will exclude any styles unrelated to the tutorial.

<nav class="navbar">
  <ul class="menu">
    <li>
      <a href="#">
        Electronics
        <!-- FontAwesome icon -->
        <i class="fa fa-angle-down"></i>
      </a> 
    </li>

    <!-- ... More nav items here... -->

  <ul>
</nav>

The navbar class is responsible for centering our navigation bar in the available space, but I’m going to focus on the menu class where I will use flexbox.

I want my navigation items to be laid out horizontally. Also, I want each item to be spaced equally and shrink as needed if there is not enough space.

First, I need to establish a flex formatting context on the .menu element, which I’ll do with display: flex. Now, all the direct children of the .menu element (which is the flex container) will be flex items.

Next, I want the menu items to be equal in width. I’ve added flex: 1 to make them grow uniformly with equal width. Here is the code:

.navbar .menu {
  display: flex;
  position: relative;
}

.navbar .menu li {
  flex: 1;
  display: flex;
  text-align: center;
}

.navbar .menu a {
  flex: 1;
  justify-content: center;
  color: #ffffff;
  padding: 20px;
}

Looking at the code, you might be wondering why I repeated display: flex for all the flex items (.navbar .menu li).

In the demo, when you hover over a menu item, its background color changes. If I don’t set the display property of the flex items to flex, then only the li elements will have equal width and not the content inside them (i.e. some highlighted part will be clickable and others will not).

To make the content expand to the full width of its parent, I made the flex items themselves into flex containers. With this in place, I can then make each nested a element grow as wide as its parent (using flex: 1), thus making the full highlighted area clickable.

Alternatively, I could have also achieved this without making li elements flex containers, but I’d have to use three additional properties (display: inline-block, width: 100%, box-sizing: border-box), which I would prefer to avoid.

This demo shows what is done so far.

With a mere five CSS Flexbox properties, the navigation bar is ready. As you can see, this is a clean solution.

In the next section, I’ll show you how to build a single section of the mega navigation.

Building a Single Drop-down Section

Below is the markup I’m going to use to build a single drop-down section, which will extend to multiple sections. The container__list item will be duplicated to create the other sections.

<ul class="container">
  <!-- single column -->
  <div class="container__list">
    <!-- menu item -->
    <div class="container__listItem">
      <div>Televisions</div>
    </div>

    <!-- ... other menu items here -->

  </div>
</ul>

The container is the flex container and each direct child (i.e. container__list) is a flex item. Each container__list has multiple navigation items, each wrapped by container__listItem. I’ve wrapped the content in a div, which I’ll come back to later.

Here is the CSS:

.container {
  /* initially hidden; display:flex on hover */
  display: none;
  position: absolute;
  top: 56px;
  left: 0;
  right: 0;
  background-color: #ffffff;
  padding: 20px;
  text-align: left;
}

.container__list {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
}

.container__listItem {
  flex: 0 0 25%;
  padding: 10px 30px;
}

.container__listItem > div {
  color: #DB6356;
}

Notice that I’ve used the flex-wrap property on container__list but I didn’t use this for the navigation bar itself. As mentioned earlier, I don’t want the navigation bar items to wrap to the next line when there is a shortage of space. Instead, they shrink equally when the available horizontal space is reduced.

For the container__list items, however, the requirement is the other way around. I want my list item to use 25% of the space, thus accommodating a maximum of four items per row, which I can accomplish using flex-wrap: wrap.

I’ve also set flex-grow to 0. This is useful because it prevents the items that are less than four from being equally spaced. By setting it to 0 I’m forcing the items to stick with 25% of the space.

Now what about the content wrapped in div?. I wanted to cover a case where you may want to prevent content overflowing. This is pretty straightforward when your content is directly inside the flex child (i.e. container__listItem). I can use following code to replace clipped text with an ellipsis (“…”).

.example {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

But in this case I’ve put the content inside a div, which is wrapped by a container__listItem. Thus, the above solution won’t work. The article Flexbox and Truncated Text offers a solution. In the code below, the lines below the “updated” comments in each declaration block are the ones that deal with this problem:

.container__list {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  /* updated */
  min-width: 0;
}

.container__listItem {
  flex: 0 0 25%;
  padding: 10px 30px;
  /* updated */
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.container__listItem > div {
  color: #DB6356;
  /* updated */
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

Limiting a Single Drop-down Section to Three Columns

At this stage, the bulk of the work is now done. For this remaining section, I’ll add another drop-down section that I’ll force to be limited to three columns of items.

As mentioned, I’ll replicate container__list twice and will use it in a new drop-down section called “Appliances”. This is done for demo purposes. In a real world example, you might have a generated list via JavaScript or using a back-end language.

I’ll add a class of has-multi to tweak the user interface. Using this class I need to override a few properties.

.container.has-multi .container__list {
  flex-basis: 33.333%;
}

.container.has-multi .container__list:not(:last-child) {
  border-right: solid 1px #f3f3f3;
  margin-right: 20px;
}

.container.has-multi .container__listItem {
  flex-basis: 100%;
}

Here I’ve set flex-basis to 33.333% as I want to display three sections in the container. I’ve changed only flex-basis, but the other 2 properties flex-grow and flex-shrink are already inherited from the single section code.
This gives me flexibility when I have a container__list less than three. In the case of only two lists, the container__list items will grow and distribute space among themselves. That is, each will hold 50% of the total width.

Note that .container__listItem is set to flex-basis: 100%, which ensures a single column in the container__list. I could have used 50% to allow two columns in each section.

A Few Notes on Mega Menu Usability

I’ve chosen mega menus as my example without much thought on its usability. Before using such a feature, I’ve provided a few resources that discuss the pros and cons.

In my opinion, mega menu navigation is useful for displaying all options and this style of navigation can be used effectively on e-commerce websites. I like Intel’s navigation.

Final Words

One thing to note is that the final mega menus from this tutorial aren’t fully responsive. The main menu bar will appear on smaller screens but the mega menus will not be available, with only the top-level links functional. For the purposes of this tutorial, this should suffice. Feel free to fork the demo and improve on this if you like.

A mega drop-down menu navigation system is a decent way to demonstrate the power and simplicity of Flexbox, which I hope I have conveyed in this tutorial. As you can see, flexbox is useful for more than just centering content.

If you’ve used a different flexbox-based technique to build a mega menu system, feel free to tell us about it in the comments.

Update: I’ve built a responsive mobile-friendly version of these mega menus, which you can find in this CodePen demo.

Frequently Asked Questions (FAQs) about Building Mega Menus with Flexbox

How can I make my mega menu responsive using Flexbox?

Making your mega menu responsive using Flexbox is quite straightforward. You can use media queries to adjust the layout of your menu based on the screen size. For instance, you can stack the menu items vertically on smaller screens and display them horizontally on larger screens. You can also use the ‘flex-wrap’ property to allow the menu items to wrap onto multiple lines if necessary. Remember to test your menu on different devices to ensure it looks good and functions well on all screen sizes.

Can I use Flexbox to create a multi-level mega menu?

Yes, you can use Flexbox to create a multi-level mega menu. You can nest flex containers within each other to create multiple levels of navigation. Each level can be displayed or hidden using CSS and JavaScript. This allows you to create complex navigation structures that are still easy to navigate and understand.

How can I add animations to my Flexbox mega menu?

You can add animations to your Flexbox mega menu using CSS transitions and transforms. For example, you can use a transition to smoothly animate the opening and closing of submenus. You can also use transforms to animate the movement of menu items. Remember to keep your animations subtle and consistent to avoid confusing or distracting users.

How can I improve the accessibility of my Flexbox mega menu?

Improving the accessibility of your Flexbox mega menu involves several steps. First, ensure that your menu is keyboard navigable. This means that users should be able to navigate through the menu using the tab and arrow keys. Second, use ARIA roles and properties to provide additional information about the menu to assistive technologies. Third, ensure that your menu has sufficient contrast and is easy to read.

Can I use Flexbox to create a sticky mega menu?

Yes, you can use Flexbox to create a sticky mega menu. You can use the ‘position: sticky’ CSS property to make your menu stick to the top of the page when the user scrolls. This ensures that the menu is always visible and accessible, even on long pages.

How can I add icons to my Flexbox mega menu?

You can add icons to your Flexbox mega menu using icon fonts or SVGs. You can use the ‘flex’ property to control the size and spacing of the icons. You can also use CSS to change the color and hover effects of the icons.

How can I add a search bar to my Flexbox mega menu?

You can add a search bar to your Flexbox mega menu by creating a flex item that contains a form with an input field and a submit button. You can use the ‘flex’ property to control the size and position of the search bar. You can also use CSS to style the search bar to match the rest of your menu.

How can I add dropdowns to my Flexbox mega menu?

You can add dropdowns to your Flexbox mega menu by creating nested flex containers. You can use CSS to hide the dropdowns by default and display them when the user hovers over the parent menu item. You can also use JavaScript to add additional interactivity to the dropdowns, such as closing them when the user clicks outside of them.

How can I add a mobile menu toggle to my Flexbox mega menu?

You can add a mobile menu toggle to your Flexbox mega menu by creating a button that toggles the display of the menu. You can use media queries to hide the toggle on larger screens and display it on smaller screens. You can also use JavaScript to toggle the ‘display’ property of the menu when the button is clicked.

How can I optimize the performance of my Flexbox mega menu?

Optimizing the performance of your Flexbox mega menu involves several steps. First, ensure that your CSS and JavaScript are minified and compressed to reduce their file sizes. Second, use CSS transitions and transforms for animations instead of JavaScript, as they are more performant. Third, use media queries to load different styles and scripts based on the screen size, reducing the amount of unnecessary code that is loaded.

Kalpesh SinghKalpesh Singh
View Author

Kalpesh Singh is a developer, inclusive web design advocate, and cares about open standards. He enjoys his responsibility at CleverTap as a front-end developer and is always ready to go the extra mile. Outside of the office, he enjoys traveling, reading fiction, and street food.

AdvancedCSScss flexboxflexboxLouisLmega menu
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week