Let’s build a hamburger menu button for mobile responsiveness so users can open and close the navigation. We will also learn how to add assistive technology features.
- First, we will hide the span menu, making it only available for screen readers.
<button><span class="sr-only">Menu</span></button> //<--------------
<nav>
<ul>
<li>Home</li> <li>Portfolio</li> <li>About</li>
</ul>
</nav>
2. Next, add the class class=”mobile-nav-toggle”
so we can select it.
<button class="mobile-nav-toggle" > //<--------------
<span class="sr-only">Menu</span>
</button>
<nav>
<ul>
<li>Home</li> <li>Portfolio</li> <li>About</li>
</ul>
</nav>
3. Then, add aria-controls=”primary-navigation”
<button class="mobile-nav-toggle"
aria-controls="primary-navigation"> //<--------------
<span class="sr-only">Menu</span>
</button>
<nav>
<ul>
<li>Home</li> <li>Portfolio</li> <li>About</li>
</ul>
</nav>
4. Finally, match the aria-controls
using an id
for the <ul>
, (because it doesn’t look at class
, only id
) so that when the menu is clicked, the entire navigation will open and close.
<button class="mobile-nav-toggle"
aria-controls="primary-navigation">
<span class="sr-only" >Menu</span>
</button>
<nav>
<ul id="primary-navigation" > //<--------------
<li>Home</li> <li>Portfolio</li> <li>About</li>
</ul>
</nav>
5. add aria-expanded
attribute. The menu is closed when it’s false, when it’s clicked, it will open. We will used javascript to change the value to true
or false
.
<button class="mobile-nav-toggle"
aria-controls="primary-navigation">
<span class="sr-only"
aria-expanded="false">Menu</span> //<--------------
</button>
<nav>
<ul id="primary-navigation" >
<li>Home</li> <li>Portfolio</li> <li>About</li>
</ul>
</nav>
Let’s turn the horizontal navigation to a vertical navigation.
- look for the navigation classes in CSS because we already wrote some.
.
.
.
.primary-navigation {
--gap: 8rem;
--underline-gap: 2rem;
list-style: none;
padding: 0;
margin: 0;
}
.
.
.
2. Delete --gap
.primary-navigation {
--underline-gap: 2rem;
list-style: none;
padding: 0;
margin: 0;
}
3. add flex-direction: column;
.primary-navigation {
--underline-gap: 2rem;
list-style: none;
padding: 0;
margin: 0;
flex-direction: column; //<--------------
}
4. add position:....
so the navigation isn’t creating new unnecessary space.
.primary-navigation {
--underline-gap: 2rem;
position: fixed; //<--------------
list-style: none;
padding: 0;
margin: 0;
flex-direction: column;
}
5. add background so we can see the menu
backdrop-filter: blur(2em);
6. inset: top, right, bottom, left
for position.
.primary-navigation {
--underline-gap: 2rem;
position: fixed;
inset: 0 0 0 20%; //<--------------top, right, bottom, left
//similar to ------ /* left: 7em; */
list-style: none;
padding: 3em;
margin: 0;
flex-direction: column;
backdrop-filter: blur(2em);
right: 0em;
}
problem: the button is on top of the menu
solution: z-index
.primary-navigation {
--underline-gap: 2rem;
position: fixed;
z-index: 1000000; //<--------- high number
inset: 0 0 0 20%;
/* left: 7em; */
list-style: none;
padding: 3em;
margin: 0;
flex-direction: column;
backdrop-filter: blur(2em);
right: 0em;
}
add padding: min(20rem, 20vh) , whichever value is smaller, we will go with that.
padding: min(20rem, 20vh) 2rem;
- Adding Media Queries for hamburger menu:
For the hamburger menu, we are using max-width
instead of min-width
(mobile-first approach) to avoid overwriting the intricately crafted navigation code.
- Considerations for Complexity:
- Larger Screens:
Often, use min-width
(mobile first approach) to add complexity for larger sizes.
- Navigation Elements:
For navigation and hamburger menus, we introduce more complexity for smaller screens, hence we use max-width
.
.primary-navigation {
--underline-gap: 2rem;
list-style: none;
padding: 0;
margin: 0;
}
@media (max-width: 35rem) {
.primary-navigation {
--underline-gap: 2rem;
position: fixed;
z-index: 1000;
inset: 0 0 0 30%;
background: black;
list-style: none;
padding: min(20rem, 15vh) 2rem;
margin: 0;
flex-direction: column;
}
}
@supports
//use this
.primary-navigation {
backdrop-filter: blur(2em);
}
//if this attribute and value are supported then use this
@supports(backdrop-filter: blur(2em)){
.primary-navigation {
backdrop-filter: blur(2em);
}
}
🍔
- hide the toggle on the desktop side, which is in the global scope.
.mobile-nav-toggle {
display: none;
}
2. in the media query scope, style the hamburger button using the background-image
attribute.
.mobile-nav-toggle {
display: none;
}
@media (max-width: 45rem){
.....
.mobile-nav-toggle {
border: 0;
display: block;
position: absolute;
z-index:20000000000;
right: 2em;
top: 2em;
background-color: transparent;
background-image: url(./assets/shared/icon-hamburger.svg);
background-size: 100%;
width: 3em;
background-repeat: no-repeat;
aspect-ratio: 1/1;
}
}
yay we get the burger button!
problem: need to make the hamburger button a toggle switch.
solution: let’s solve it with Javascript to close the menu
html
<script src="index.js" defer></script>
html .primary-navigation tag, add new custom attribute called, burger-on
and set it as false.
<ul id="primary-navigation" burger-on="false" class="primary-navigation underline-indicators flex">
js
// javascript
const toggle = document.querySelector(".mobile-nav-toggle")
const navi = document.querySelector(".primary-navigation")
toggle.addEventListener("click", () => {
let burgerOn = navi.getAttribute("burger-on")
console.log(burgerOn)
if(burgerOn==="false"){
// toggle.style.background-image="./shared/icon-close.svg"
navi.setAttribute("burger-on", true)
}
else {
navi.setAttribute("burger-on", false)
}
})
so now we get the toggle going
@media (max-width: 45rem){
.primary-navigation {
...
}
.primary-navigation[burger-on="true"]{
display: none;
}
reference: Kevin Powell’s — — https://v2.scrimba.com/build-a-space-travel-website-c014/~016