بروزرسانی: 22 آبان 1404
How to Build a Responsive Navigation Bar With Flexbox
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\xa0to the viewport size\xa0while 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 bar will have three different layouts, depending on the viewport size:
- a\xa0mobile layout\xa0in 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\xa0tablet layout\xa0in which we\xa0will 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\xa0desktop layout\xa0in 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\xa0the mobile layout first. Then, we will add the tablet- and desktop-specific CSS using\xa0min-width\xa0media queries.
The navigation bar will also have a JavaScript-based dropdown submenu that opens and closes when the user clicks the parent menu item.
Here’s how the menu will look on mobile:



Here’s the tablet version:



And, this is how it will look on desktop:



You can also test, fork, and play around with\xa0the interactive demo on CodePen:
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 for Your Flexbox Navbar
The HTML is a simple\xa0<ul>\xa0list, as you can see below. The\xa0.menu\xa0class 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\xa0Log In\xa0and\xa0Sign Up\xa0buttons will come first on mobile, but will be displayed at the end of the menu on desktop. We will achieve this effect\xa0by making use of\xa0flexbox’s ordering properties.
1 | <nav>
|
2 | <ul class="menu"> |
3 | <li class="logo"><a href="#">Creative Mind Agency</a></li> |
4 | <li class="item"><a href="#">Home</a></li> |
5 | <li class="item"><a href="#">About</a></li> |
6 | <li class="item has-submenu"> |
7 | <a tabindex="0">Services</a> |
8 | <ul class="submenu"> |
9 | <li class="subitem"><a href="#">Design</a></li> |
10 | <li class="subitem"><a href="#">Development</a></li> |
11 | <li class="subitem"><a href="#">SEO</a></li> |
12 | <li class="subitem"><a href="#">Copywriting</a></li> |
13 | </ul>
|
14 | </li>
|
15 | <li class="item has-submenu"> |
16 | <a tabindex="0">Plans</a> |
17 | <ul class="submenu"> |
18 | <li class="subitem"><a href="#">Freelancer</a></li> |
19 | <li class="subitem"><a href="#">Startup</a></li> |
20 | <li class="subitem"><a href="#">Enterprise</a></li> |
21 | </ul>
|
22 | </li>
|
23 | <li class="item"><a href="#">Blog</a></li> |
24 | <li class="item"><a href="#">Contact</a> |
25 | </li>
|
26 | <li class="item button"><a href="#">Log In</a></li> |
27 | <li class="item button secondary"><a href="#">Sign Up</a></li> |
28 | <li class="toggle"><a href="#"><i class="fas fa-bars"></i></a></li> |
29 | </ul>
|
30 | </nav> |
You have probably noticed that menu items with a submenu (“Services” and “Plans”) have an\xa0<a> tag without an\xa0href attribute. We do this because\xa0these “empty” parent menu items don’t lead to any other page–they just open and close the submenu. Using the anchor tag without href is permitted and prevents the page from jumping up on small screens when the user clicks the empty menu item to open or close the submenu.
We also\xa0add the tabindex="0" attribute to <a> elements without a href attribute. This is because\xa0empty <a> tags are omitted from the default tab order, so we need to put them back to the tabbing order with the tabindex attribute to keep the menu keyboard-accessible.
Note: the toggle button at the end of the list uses a Font Awesome icon. To make the demo work, you’ll need to add the\xa0Font Awesome\xa0library to the\xa0<head>\xa0section of the HTML document\xa0from CDN using\xa0the code below. (If you want to make the menu work offline, you’ll need to\xa0host Font Awesome locally.)
1 | <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css"> |
2. Add Some Basic Styling to Your Flexbox Navigation Bar
For basic styling, I’ve set some default values and colors, however, you can use any of your own style rules as well:
1 | /* Basic styling */
|
2 | * { |
3 | box-sizing: border-box; |
4 | padding: 0; |
5 | margin: 0; |
6 | }
|
7 | body { |
8 | font-family: sans-serif; |
9 | font-size: 16px; |
10 | }
|
11 | nav { |
12 | background: #222; |
13 | padding: 0 15px; |
14 | }
|
15 | a { |
16 | color: white; |
17 | text-decoration: none; |
18 | }
|
19 | .menu, |
20 | .submenu { |
21 | list-style-type: none; |
22 | }
|
23 | .logo { |
24 | font-size: 20px; |
25 | padding: 7.5px 10px 7.5px 0; |
26 | }
|
27 | .item { |
28 | padding: 10px; |
29 | }
|
30 | .item.button { |
31 | padding: 9px 5px; |
32 | }
|
33 | .item:not(.button) a:hover, |
34 | .item a:hover::after { |
35 | color: #ccc; |
36 | } |
3.\xa0Start With the Mobile Navigation
As our navigation will be mobile-first, we start with the mobile layout. Most responsive flexbox navigation bar menus use column-based layouts for mobile, as menu items can be quickly packed below each other by adding the flex-direction: column;\xa0rule to the flex container. Even though this is an excellent solution, we won’t use it in our example.\xa0
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\xa0menu items such as\xa0Home\xa0and\xa0About\xa0span across the entire container using the\xa0width: 100%;\xa0rule. 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.\xa0
In the CSS below, we also use the\xa0justify-content\xa0and\xa0align-items\xa0properties to\xa0align the flex items horizontally and vertically. Besides this, we hide the\xa0.item\xa0elements using the\xa0display: none;\xa0rule. Menu items will be only revealed when the user clicks the toggle button. The\xa0.active\xa0class is not in the HTML code, we will dynamically add it with JavaScript.
1 | /* Mobile menu */
|
2 | .menu { |
3 | display: flex; |
4 | flex-wrap: wrap; |
5 | justify-content: space-between; |
6 | align-items: center; |
7 | }
|
8 | .menu li a { |
9 | display: block; |
10 | padding: 15px 5px; |
11 | }
|
12 | .menu li.subitem a { |
13 | padding: 15px; |
14 | }
|
15 | .toggle { |
16 | order: 1; |
17 | font-size: 20px; |
18 | }
|
19 | .item.button { |
20 | order: 2; |
21 | }
|
22 | .item { |
23 | order: 3; |
24 | width: 100%; |
25 | text-align: center; |
26 | display: none; |
27 | }
|
28 | .active .item { |
29 | display: block; |
30 | }
|
31 | .button.secondary { /* divider between buttons and menu links */ |
32 | border-bottom: 1px #444 solid; |
33 | } |
As you can see above, we have also changed the order of menu items with the help of the\xa0order\xa0property. Our\xa0HTML outline follows a logical order. This is how we want screen reader users and search engine bots to go through the menu.\xa0
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 (“Log In” and “Sign Up”)\xa0before regular menu items. So, we set up the following order:
.logo\xa0gets the\xa0order: 0;\xa0value, as it will be the first item (however, as this is the default value of\xa0order, we don’t need to add it to the CSS),.toggle\xa0gets\xa01, as it comes right after\xa0.logo,.item.button\xa0belonging to the\xa0Log In\xa0and\xa0Sign Up\xa0buttons gets\xa02,- and\xa0
.item\xa0belonging to the rest of menu items\xa0gets\xa03.
4. Style the Submenu in Your Responsive Navbar
As this is mobile-first navigation, we’ll primarily style the submenu with mobile screens in mind. This is a great technique, as it’s usually harder to create a user-friendly submenu for small screens than for larger ones. Then, we can use the same submenu layout for tablet screens as well. For the desktop, we’ll only need to change the positioning of the submenu.
By default, the submenu is set to display: none; and will be only revealed\xa0when the user clicks the parent menu item. We will add the required JavaScript functionality in the next two steps before moving on to the tablet menu.
1 | /* Submenu up from mobile screens */
|
2 | .submenu { |
3 | display: none; |
4 | }
|
5 | .submenu-active .submenu { |
6 | display: block; |
7 | }
|
8 | .has-submenu i { |
9 | font-size: 12px; |
10 | }
|
11 | .has-submenu > a::after { |
12 | font-family: "Font Awesome 5 Free"; |
13 | font-size: 12px; |
14 | line-height: 16px; |
15 | font-weight: 900; |
16 | content: "\\f078"; |
17 | color: white; |
18 | padding-left: 5px; |
19 | }
|
20 | .subitem a { |
21 | padding: 10px 15px; |
22 | }
|
23 | .submenu-active { |
24 | background-color: #111; |
25 | border-radius: 3px; |
26 | } |
As you can see above, now we add the Font Awesome icons using CSS instead of HTML. These icons we add using the ::after pseudo-element will be the little down arrows shown next to each menu item that has a submenu.\xa0
If you remember we added the Font Awesome icon for the toggle button with HTML in Step 1. This is because the toggle button will be targeted with JavaScript, so it has to be present in the DOM. However, the down arrows here are just style elements that indicate the presence of the submenu. Since no functionality relies on them, it’s better to add them with CSS.
5. Add the Toggle Functionality with JavaScript to Your Flexbox Navbar
We’ll set up the toggle functionality by adding a click event listener to the toggle button that opens and closes the menu on mobile. In the\xa0JavaScript code, we will\xa0use the ES6 syntax that gives us access to the const\xa0and let notation and the for...of loop and already has good browser support.
For the custom JavaScript, create an empty\xa0script.js file and add it to the HTML in your responsive navigation menu before the closing </body> tag:
1 | <script src="script.js"></script> |
And here’s the JavaSript code responsible for the toggle functionality:
1 | const toggle = document.querySelector(".toggle"); |
2 | const menu = document.querySelector(".menu"); |
3 | |
4 | /* Toggle mobile menu */
|
5 | function toggleMenu() { |
6 | if (menu.classList.contains("active")) { |
7 | menu.classList.remove("active"); |
8 | |
9 | // adds the menu (hamburger) icon
|
10 | toggle.querySelector("a").innerHTML = "<i class=’fas fa-bars’></i>"; |
11 | } else { |
12 | menu.classList.add("active"); |
13 | |
14 | // adds the close (x) icon
|
15 | toggle.querySelector("a").innerHTML = "<i class=’fas fa-times’></i>"; |
16 | }
|
17 | }
|
18 | |
19 | /* Event Listener */
|
20 | toggle.addEventListener("click", toggleMenu, false); |
- First, we select the menu and the toggle button\xa0using the\xa0
querySelector()\xa0method so that we can access them with JavaScript.\xa0 - Then, we add the custom
toggleMenu()function that will be called when the toggle is clicked.\xa0 - Lastly, we add the event listener that will be listening to the click event using the
addEventListener()method.
6. Add the Dropdown Menu Flexbox Functionality with JavaScript
Now, when the user clicks the toggle button, the menu is activated and deactivated, however, the submenu is still hidden. We will add this functionality with the following JavaScript:
1 | const items = document.querySelectorAll(".item"); |
2 | |
3 | /* Activate Submenu */
|
4 | function toggleItem() { |
5 | if (this.classList.contains("submenu-active")) { |
6 | this.classList.remove("submenu-active"); |
7 | } else if (menu.querySelector(".submenu-active")) { |
8 | menu.querySelector(".submenu-active").classList.remove("submenu-active"); |
9 | this.classList.add("submenu-active"); |
10 | } else { |
11 | this.classList.add("submenu-active"); |
12 | }
|
13 | }
|
14 | |
15 | /* Event Listeners */
|
16 | for (let item of items) { |
17 | if (item.querySelector(".submenu")) { |
18 | item.addEventListener("click", toggleItem, false); |
19 | item.addEventListener("keypress", toggleItem, false); |
20 | }
|
21 | }
|
Here, we add the .submenu-active class to each menu item with\xa0a submenu when the user clicks it.\xa0
- First, we select all menu items with the
querySelectorAll()method that returns a node list (rather than a single element likequerySelector()).\xa0 - In the custom
toggleItem()function, we add and remove.submenu-activeto/from the clicked element. Note that in theelse ifblock, we remove the class from every other flex menu item that was previously opened. This way, it won’t happen that two submenus are open at the same time, as they can cover each other on the desktop. - Finally, we loop through the
itemsclassList using a\xa0for...ofloop. Within theifblock, we add two\xa0event listeners to menu items that have a submenu: one for theclickevent for regular users who access the menu by clicking or tapping,\xa0and one for thekeypressevent for keyboard users.
7. Create the Tablet Menu with Flexbox
We’ll create the tablet layout using a\xa0min-width media query. On a tablet, four menu items will be visible by default: the logo, the two call-to-action buttons (“Log In” and “Sign Up”), and the toggle. To make everything pretty,\xa0our CSS will:
- change the\xa0
orderof the flexbox menu items to adapt the layout to tablet viewports, - realign the items (see the explanation below),
- make the\xa0Log In\xa0and\xa0\xa0Sign Up buttons look like real buttons (in the mobile layout, they look like links, as they are part of the toggleable flexbox responsive dropdown list).
In code:
1 | /* Tablet menu */
|
2 | @media all and (min-width: 700px) { |
3 | .menu { |
4 | justify-content: center; |
5 | }
|
6 | .logo { |
7 | flex: 1; |
8 | }
|
9 | .item.button { |
10 | width: auto; |
11 | order: 1; |
12 | display: block; |
13 | }
|
14 | .toggle { |
15 | flex: 1; |
16 | text-align: right; |
17 | order: 2; |
18 | }
|
19 | /* Button up from tablet screen */
|
20 | .menu li.button a { |
21 | padding: 10px 15px; |
22 | margin: 5px 0; |
23 | }
|
24 | .button a { |
25 | background: #0080ff; |
26 | border: 1px royalblue solid; |
27 | }
|
28 | .button.secondary { |
29 | border: 0; |
30 | }
|
31 | .button.secondary a { |
32 | background: transparent; |
33 | border: 1px #0080ff solid; |
34 | }
|
35 | .button a:hover { |
36 | text-decoration: none; |
37 | }
|
38 | .button:not(.secondary) a:hover { |
39 | background: royalblue; |
40 | border-color: darkblue; |
41 | }
|
42 | } |
In the tablet layout, menu items are aligned differently. 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\xa0flex: 1;\xa0CSS rule. The\xa0flex\xa0property is a shorthand for\xa0flex-grow,\xa0flex-shrink, and\xa0flex-basis. It can exist with many different value combinations. When it’s declared\xa0with only one value, it belongs to\xa0flex-grow, with\xa0flex-shrink\xa0and\xa0flex-basis\xa0keeping their default values.
In the CSS above, we have added the\xa0flex: 1;\xa0rule to the\xa0.logo\xa0and\xa0.toggle\xa0elements. In this way, we can tell the browser that if there’s any positive space on the screen, we want to share it\xa0between these two elements. As the\xa0Log In\xa0and\xa0Sign Up\xa0buttons retain their default\xa00\xa0value for\xa0flex-grow, they won’t get anything from the extra space. So,\xa0they will stay in the center of the container, as they adhere to\xa0the\xa0justify-content: center;\xa0rule set on the flex container.
8. Create the Desktop Flex Menu
The desktop flexbox navbar menu hides the toggle, sets back the original order and natural width of each item, and repositions the submenu.\xa0
It’s important to keep in mind that the\xa0tablet-specific\xa0rules also apply to the desktop menu. This is because here, the viewport width is larger than both 700px\xa0and\xa0960px, so both media queries take effect. So,\xa0.logo\xa0retains its\xa0flex: 1;\xa0property and\xa0pushes the rest of the items\xa0to the end of the container.
1 | /* Desktop menu */
|
2 | @media all and (min-width: 960px) { |
3 | .menu { |
4 | align-items: flex-start; |
5 | flex-wrap: nowrap; |
6 | background: none; |
7 | }
|
8 | .logo { |
9 | order: 0; |
10 | }
|
11 | .item { |
12 | order: 1; |
13 | position: relative; |
14 | display: block; |
15 | width: auto; |
16 | }
|
17 | .button { |
18 | order: 2; |
19 | }
|
20 | .submenu-active .submenu { |
21 | display: block; |
22 | position: absolute; |
23 | left: 0; |
24 | top: 68px; |
25 | background: #111; |
26 | }
|
27 | .toggle { |
28 | display: none; |
29 | }
|
30 | .submenu-active { |
31 | border-radius: 0; |
32 | }
|
33 | } |
9.\xa0Let Users Close the Submenu By Clicking Anywhere on the Page
Now there’s only one step back. As the dropdown menu is activated on the click event, it doesn’t close automatically when the user hovers away from the top menu item. This is especially annoying on desktops where the dropdown menu flexbox can cover the content.\xa0
So, it would be nice to enable users to close the submenu by clicking anywhere on the screen. We can add the feature with JavaScript:
1 | /* Close Submenu From Anywhere */
|
2 | function closeSubmenu(e) { |
3 | if (menu.querySelector(".submenu-active")) { |
4 | let isClickInside = menu |
5 | .querySelector(".submenu-active") |
6 | .contains(e.target); |
7 | |
8 | if (!isClickInside && menu.querySelector(".submenu-active")) { |
9 | menu.querySelector(".submenu-active").classList.remove("submenu-active"); |
10 | }
|
11 | }
|
12 | }
|
13 | |
14 | /* Event listener */
|
15 | document.addEventListener("click", closeSubmenu, false); |
The custom closeSubmenu() function checks if there’s an open submenu on the screen, and if yes, it also checks if the user clicked inside of it with the help of the target property. If the user clicked anywhere else on the screen, the .submenu-active class will be removed, and the submenu will close itself. We add the event listener to the document object, as we want to listen for clicks on the whole page.
You’ve Built a\xa0Responsive Navigation Bar With Flexbox and JavaScript!
Our mobile-first, responsive navigation bar with flexbox is up and running in three different layouts.\xa0
Here’s a reminder of the end result:
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.
Useful Resources to Learn How to Create Responsive Menus
For a list of best practices you should consider when building responsive navigation, or if you need help getting started with event listeners in JavaScript, take a look at these beginners’ guides:
Lastly,\xa0if 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:
منبع: https://webdesign.tutsplus.com/how-to-build-a-responsive-navigation-bar-with-flexbox--cms-33535t