CSS Foundations

Mobile Navigation Menu

CSS Foundations

Check out a free preview of the full CSS Foundations course

The "Mobile Navigation Menu" Lesson is part of the full, CSS Foundations course featured in this preview video. Here's what you'd learn in this lesson:

Emma walks through implementing a hamburger menu for the application's mobile navigation. Hiding and showing the navigation menu is also covered in this segment


Transcript from the "Mobile Navigation Menu" Lesson

>> Okay, so I mean, admittedly that's not terrible. Look at that, it's our mobile nav, it's not beautiful, not building the world's most beautiful website, but it is functional, so, What we want now is when we click this menu icon-
>> I think there is align-item, align-content as well.

>> Indeed, yeah, CSS tricks has fantastic articles on grid and flexbox. If you ever get confused, I can absolutely recommend that. Okie dokie, so we're almost there. What we wanna do, click on this menu icon and have the mobile nav pop up, right? Also, I had mentioned that the width was 21 pixels on this icon, but I had set it to 33 in the grid column.

It should be 33 pixels, right? So I'm gonna actually fix this. When I go into the inline SVG, I want the width to be 33, let's see what happens. That did not do anything, did it? Width 33. Or was it supposed to be height 33, let's find out, let's try that, 33.

No, it still doesn't like me. Okay, and my icon's the wrong size now. Well, that's silly, what we're gonna do is we're gonna check myself because I wanna get that right. Let's see here. Our menu has a width of 33 and 36, aha, okay, so I don't need to be editing the viewBox as well.

Let's try that again. Scrub the dimensions from the repo, I wanna make sure that it's right when you're referring back to it. So width 33, height 36, let's try that. Width 33, height 36. See how that looks. Okay, that's better. So now that that is fixed, let's get that menu showing up when we click the icon.

So first, instead of display: none on our nav, which we did set in base, where did you go? Here we go, instead of display: none, we do want to display this navigation. Now, we're gonna play with the position. It is much more performant to transition a fully width element from left to right than it is to transition the width of something.

So if we changed the width from 0 pixels to, I don't know, 100 view width, that would be much less performant because we're repainting every time, right? So we want it to be that full view width, just outside the balance of our viewport. So that's how we're gonna approach this.

To do that, we're gonna use position: absolute, right? Remember that's gonna remove it from the document flow. So I want the width of this nav to be 100 view width, take up the entire viewport width, height: 100 viewport height, right? I also want to move this. Well, first of all, let's change the background.

So if we look at our design again, we can see when the menu is open, it has a solid background of orange. So let's go ahead and set that now, background, we'll set it to the --color-primary, Right? It's there, It's just not in the right place. So let's fix that.

Let's set the top and the left value. So let's try 60 pixels and let's set the left value to 0%. Let's see what happens. Okay, that's not horrible, right? If we look at our design, we still wanna have this header, right? So that's why we set top to 60 pixels because we wanna account for the height of that header, we still wanna see it.

So here we've got our header, and here is our nav, right? It's taken up that full viewport height and width. Let's also give it a little bit of padding, so our items, they're not gonna be right up against the edges there. Now, we also want the menu items to be bigger, this looks kinda silly.

And we want them to be much bigger and vertically on top of each other, so let's fix that. So, nav_list, first of all, let's address the list. We want the flex-direction of this flex container to be column instead of row. So let's change that first, flex-direction is column, right?

List items are now in a column. Let's also justify-content: space-around. This will be more apparent when we change the font size. I'm also gonna set a height on this nav__list to 80%. I don't want it to be the full height of its container. Okay, last thing is to set the font size and font weight of our nav items to be much bigger, just like our design.

So nav_list-item, let's set font size to 60 pixels and see what happens, we'll make it bold. Okay, well, that looks pretty close to our design, not terrible. So now we don't wanna show this menu unless our button is clicked, right? So let's actually take this nav and let's move it off screen.

Let's move it outside the bounds of our viewport until we're ready for it. So let's go back here, we currently have left at 0%, let's move that to -100%, that's gonna move it off the screen, right? I've done something silly here, instead of padding all around, we just want padding top, my mistake, right?

Okay, now our nav is off the screen, you can see it's still there, it's just outside the bounds of our viewport. And then when we click that menu icon, then we want it to become visible, right? The easiest way I found to do this is to create a class that will be applied when we want it to be.

So nav--visible, we'll call it. When we want that nav to be visible, then we'll set the left value to 0, so it'll be in view, right? Okay, now we're gonna have to add just a small amount of JavaScript. And it's okay if you're unfamiliar with JavaScript, I'll walk you through what's going on.

So inside of our index file here, at the bottom, we're gonna add a script, okay? This is where we're gonna write our JavaScript. So, first, I wanna grab a handle on that navigation element so that we can actually play with whether or not it's visible. Let's do that.

So I'll create a new variable, const, call it nav. I'll use document.querySelector to grab a handle on that node, which has a class of nav, so I'm using that. I also need to grab a handle to that menu icon to make sure that we can set an event listener and check whether or not it's been clicked, right?

So I'll just do that now. So we'll call it menu, use querySelector again and grab it by the class name of menu. Now, when our menu item is clicked, let's addEventListener for that, right? When we click that, what do we wanna do? We wanna show our menu, we just created that nav--visible class, so we wanna apply that, right?

So we can do that with class list. So nav.classlist, we'll say, add, nav--visible. Okay, when we click our menu, let's show a nav. Let's see if that works. Look at that, it does work. If I refresh, you can see it again, it's there. All right, but it doesn't actually go away when we click an X icon cuz there's no X icon.

So let's fix that, let's grab that close-menu-svg. Again, we will do in line. This is the Menu icon, we'll put it right underneath there. Okay. Where did you go? It's this one. Yeah, yeah, yeah. Okay, so the class on here, we'll call this close. Again, we wanna change the width and height so that it looks a little bit nicer and is in line with our grid cell there.

So we'll change it to 30 by 34. Now by default, we need to have the close icon not shown, right? So, There are two things going on. First of all, our close icon is also orange, so that's why we're seeing things a little bit wonky here, even though it doesn't look like anything else has changed.

There is a close icon being rendered, it's just orange, so we're not seeing it. To fix that, let's go back here. So first of all, we do want our close icon to have a display of none by default. And I'm gonna put that outside that media query. So close display: none, right?

We also want specifically in the home or index file here, .home .close path we want this to be white. So let's have that same fill color like we do for our menu icon. Okay, so we shouldn't see anything yet, but what we want to happen is when we click our menu icon, our menu appears, right?

Well, we want that menu icon to go away and be replaced by that close icon when our menu is active. Stack in our script here, we're gonna add one more variable, call it close, select it with a class selector. So when the menu icon is clicked, show the nav.

We also want to hide that menu icon once the navigation is actually visible. So menu.classList.add, we haven't written this one yet, but we will, we wanna hide that menu, right? Let's go ahead and add that. And we only need this width of 840, so .menu--hide, this will be display: none, right?

So there we go, we wanna hide that menu icon when the nav is visible. And the last one we wanna do is show that close icon, right? So close.classList.add, and we'll call you close--show, right? And close--show is gonna do the same thing with that menu icon did, which is display block.

Where are you? menu, okay, .close--show display: block. Okay, let's see if it works, it does work. Okay, so walking through what we just did, cuz it was a little bit quick, right?
>> I noticed you're using block here, can we use visible too?
>> Display visible?
>> Yap.

>> I don't think display has a visible value, display css.
>> Or is it visible?
>> Let's see, I'm pretty sure it doesn't have visible.
>> Visible show, I think it's visible show.
>> Are you talking about visibility?
>> Yeah, visibility-
>> So-
>> Sure.
>> The difference between display block and display visibility, display none versus visibility hidden is that display none should remove that from the DOM, right?

And that's good because we don't want our screen readers to be like, hey, there's an icon here, or button here, right? And as a note, lwe're using SVG icons and setting click handlers on them. Realistically, we should have button elements, right? It's completing an action and the most accessible solution here is to have a button wrapping around the SVG.

So just be aware of that, I should have done that. Yeah, but that was a great question, yeah. You can use visibility, it's just that screen readers might acknowledge it. Absolutely, okay, so now our nav is visible, our X icon is there, now we just kinda have to do the opposite, right?

So when our close icon is clicked, let's go back to the state we were in before with that menu icon, so we'll just kinda do the opposite here. close.addEventListener, so we're gonna click, kinda just wanna do the opposite of everything we just did? I'm just gonna copy and paste this and kind of reverse the logic here.

So when we click our close button, we wanna remove nav--visible, we want to remove menu--hide. We want to remove close--show. So now we're seeing that, right? Reversing our logic.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now