Time for a practical exercise in flexbox! In this tutorial we will use flexbox to create a mobile-first, responsive, toggleable navigation bar with different layouts for mobile, tablet, and desktop screens.
Flexbox is Perfect for Responsive Navigation
Flexbox is a versatile layout module with which we can create one-dimensional layouts that require flexibility, such as responsive menus. Using flexbox’s ordering, alignment, and sizing properties, we can build navigation bars that adapt their layouts to the viewport size while keeping the HTML outline logical and accessible.
In this tutorial, we’ll look into how to create a responsive navigation bar with flexbox. Our flexbox navigation will have three different layouts, depending on the viewport size:
- a mobile layout in which only the logo and a toggle button will be visible by default and users can open and close the menu using the toggle,
- a tablet layout in which we will show two call-to-action buttons between the logo and toggle in the default state and the rest of the menu will remain toggleable,
- a desktop layout in which all the menu items, except for the toggle button, will be visible on the screen.
We will use media queries to detect the viewport size of the user’s browser. Our responsive navigation bar will be mobile-first, so we will create the mobile layout first. Then, we will add the tablet- and desktop-specific CSS using min-width
media queries.
Here’s how the mobile menu will look when it’s opened by the user:
Here’s the tablet version:
And, this is how our flexbox navigation will look on desktop:
The best thing about flexbox menus is that they are really very accessible, as the HTML is just a simple unordered list. So, screen reader users won’t even notice that there are different layouts, as all the styling is done with CSS and a bit of jQuery (for the toggle functionality).
You can also test the interactive demo:
New to Flexbox?
If you aren’t used to flexbox, or need a refresher, these beginner guides will give you all the skills you need to complete this tutorial:
1. Create the HTML
The HTML is a simple <ul>
list, as you can see below. The .menu
class will be the flex container and the list items will be the flex items. Their order will adapt to the viewport size of the user’s device. For example, the Log In and Sign Up buttons will come first on mobile but will be displayed at the end of the menu on desktop. We will achieve this effect by making use of flexbox’s ordering properties.
<nav> <ul class="menu"> <li class="logo"><a href="#">Invisible App</a></li> <li class="item"><a href="#">Home</a></li> <li class="item"><a href="#">About</a></li> <li class="item"><a href="#">Services</a></li> <li class="item"><a href="#">Features</a></li> <li class="item"><a href="#">Blog</a></li> <li class="item"><a href="#">Contact</a> </li> <li class="item button"><a href="#">Log In</a></li> <li class="item button secondary"><a href="#">Sign Up</a></li> <li class="toggle"><a href="#"><i class="fas fa-bars"></i></a></li> </ul> </nav>
Note: the toggle button at the end of the list uses a Font Awesome icon. You’ll need to add Font Awesome to the <head>
section of the HTML and jQuery to the end of the <body>
section to make the demo properly work.
2. Add Some Basic Styling
For basic styling, I’ve set some default values and colors, however you can use any other style rules as well:
/* Basic styling */ * { box-sizing: border-box; padding: 0; margin: 0; } body { font-family: sans-serif; } nav { background: #222; padding: 5px 20px; } ul { list-style-type: none; } a { color: white; text-decoration: none; } a:hover { text-decoration: underline; } .logo a:hover { text-decoration: none; } .menu li { font-size: 16px; padding: 15px 5px; white-space: nowrap; } .logo a, .toggle a { font-size: 20px; } .button.secondary { border-bottom: 1px #444 solid; }
3. Start with the Mobile Navigation
As our navigation will be mobile-first, we start with the mobile layout. Responsive flexbox menus usually create column-based layouts for mobile. By adding the flex-direction: column;
rule to the flex container, we can quickly pack the menu items below each other.
Although this is an excellent solution, we won’t use it in our example. Instead, we will create a wrapping row-based layout for mobile so that we can display the logo and toggle button next to each other on top of the menu.
The CSS trick here is that we make regular menu items such as Home and About span across the entire container using the width: 100%;
rule. So, flexbox will display them below each other, while the logo and toggle will retain their natural sizes and sit on top of the navbar in the same row.
In the CSS below, we also use the justify-content
and align-items
properties to align the flex items horizontally and vertically. Besides, we hide the .item
elements using the display: none;
rule. Menu items will be only revealed when the user clicks the toggle button. The .active
class is not in the HTML code, we will dynamically add it with a tiny jQuery script.
/* Mobile menu */ .menu { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; } .toggle { order: 1; } .item.button { order: 2; } .item { width: 100%; text-align: center; order: 3; display: none; } .item.active { display: block; }
As you can see above, we have also changed the order of menu items with the help of the order
property. Our HTML outline follows a logical order. This is how we want screen reader users and search engine bots to go through the menu.
However, in the mobile layout, we want to show the logo and toggle button on top of the menu. We also want to display the two call-to-action buttons before regular menu items. So, we set up the following order:
-
.logo
gets theorder: 0;
value, as it will be the first item (however, as this is the default value oforder
, we don’t need to add it to the CSS), -
.toggle
gets1
, as it comes right after.logo
, -
.item.button
belonging to the Log In and Sign Up buttons gets2
, - and
.item
belonging to the rest of menu items gets3
.
4. Create the Tablet Menu
We add the tablet layout using a min-width
media query. Here, four menu items will be visible by default: the logo, the two call-to-action buttons, and the toggle. To make everything pretty, our CSS will:
- change the
order
of the menu items to adapt the layout to tablet viewports, - realign the items (see the explanation below),
- make the Log In and Sign Up buttons look like real buttons (in the mobile layout, they are presented as links, as they are part of the toggleable dropdown list).
In code:
/* Tablet menu */ @media all and (min-width: 600px) { .menu { justify-content: center; } .logo { flex: 1; } .toggle { flex: 1; text-align: right; } .item.button { width: auto; order: 1; display: block; } .toggle { order: 2; } .button.secondary { border: 0; } .button a { padding: 7.5px 15px; background: teal; border: 1px #006d6d solid; } .button.secondary a { background: transparent; } .button a:hover { text-decoration: none; } .button:not(.secondary) a:hover { background: #006d6d; border-color: #005959; } .button.secondary a:hover { color: #ddd; } }
In the tablet layout, menu items are aligned in a different way. If you take a look at the four visible menu items, you will see that the two buttons are displayed in the center, while the logo and toggle are pushed to the left and right end of the container:
We can achieve this effect using the flex: 1;
CSS rule. The flex
property is a shorthand for flex-grow
, flex-shrink
, and flex-basis
. It can exist with many different value combinations. When it’s declared with only one value, it belongs to flex-grow
while flex-shrink
and flex-basis
keep their default values.
In the CSS above, we have added the flex: 1;
rule to the .logo
and .toggle
elements. In this way, we can indicate to the browser that if there’s any positive space on the screen, we want to share it between these two elements. As the Log In and Sign Up buttons retain their default 0
value for flex-grow
, they won’t get anything from the extra space. So, they will stay in the center of the container, as they adhere to the justify-content: center;
rule set on the flex container.
5. Create the Desktop Menu
The desktop menu hides the toggle and sets back the original order and natural width of each item.
It’s important to keep in mind that the tablet-specific rules also apply to the desktop menu. This is because here, the viewport width is larger than both 600px
and 900px
, so both media queries take effect. So, .logo
retains its flex: 1;
property and pushes the rest of the items to the end of the container.
/* Desktop menu */ @media all and (min-width: 900px) { .item { display: block; width: auto; } .toggle { display: none; } .logo { order: 0; } .item { order: 1; } .button { order: 2; } .menu li { padding: 15px 10px; } .menu li.button { padding-right: 0; } }
6. Add the jQuery Functionality
We add the toggle functionality to the mobile and tablet menus with a small jQuery script. Using a click event handler, our script detects when the user clicks or taps the toggle button. Then, with an if-else
statement, it checks if the dropdown is getting toggled on or off in the moment of the user action.
When the dropdown is toggled on, it adds the .active
class to each item. It also replaces the hamburger icon with a close icon (fa-times
), also from Font Awesome. And, when the dropdown is toggled off, it removes the .active
class from each item and changes back the icon to the original hamburger icon (fa-bars
).
$(function() { $(".toggle").on("click", function() { if ($(".item").hasClass("active")) { $(".item").removeClass("active"); $(this).find("a").html("<i class='fas fa-bars'></i>"); } else { $(".item").addClass("active"); $(this).find("a").html("<i class='fas fa-times'></i>"); } }); });
Conclusion
Our mobile-first, responsive navigation bar is up and running in three different layouts. Flexbox is a great tool to implement complex layouts without any tweaks. If you combine flexbox’s alignment, ordering, and sizing properties with media queries, you can create different layouts for different viewports without having to manipulate the HTML source code.
If you are interested in how you can use flexbox in your everyday work, have a look at these other practical tutorials–each one helps you learn by building things you can actually use: