I put together this short tutorial on how to make a hamburger menu with no js in response to the feedback on my original Twitter post. The trick is t
4 years ago
|2 min read
I put together this short tutorial on how to make a hamburger menu with no js in response to the feedback on my original Twitter post.
The trick is to use the CSS pseudo-class :target. I'm not the one who came up with that technique - saw it on stackOverflow or elsewhere.
Anyway, enjoy π!
:target
Have you heard of the CSS pseudo-class on :target?
It styles the element with an anchor id that that has been called by a link.
For example, a p with an id of home and an a link with href=#home:
<p id="home">Home</p>
<a href="#home">Go to Home</a>
p:target {
color: red;
}
When we click on the a link, the text of the targeted p changes to red.
By clicking on another link, the :target style gets hidden.
<p id="home">Home</p>
<a href="#home">Go to Home</a>
<a href="#">Go somewhere else</a>
Here's the whole html code.
I'm using material icons by adding their cdn in the head of the html file.
<head>
<!-- ... -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<!-- ... -->
<ul class="menu" id="menu">
<li><a href="#">Home</a></li>
<li><a href="#">Profile</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contacts</a></li>
<a class="close" href="#">
<span class="material-icons">
close
</span>
</a>
</ul>
<a class="hamburger" href="#menu">
<span class="material-icons">
menu
</span>
</a>
</body>
Material icons work by defining a span with material-icons class and adding a keyword between the tags:
<span class="material-icons">
close
</span>
- The ul has an id of menu. It holds the menu and the close icon link.
- The a with a class of hamburger has a href #menu, clicking on it will show the on :target style for the ul menu.
- Clicking on other links (Home, Profile, About, Contacts) and the close link will remove the on :target style of the ul.
Now we just need to add a sprinkle of CSS β¨.
The hamburger link has a position fixed to get it out of the flow of the page.
The menu has a position fixed too and a bigger z-index than the hamburger link to put the menu above the link.
For consistency, I've put the hamburger and close links on the same corner.
.hamburger {
position: fixed;
/* a large z-index puts the ham button above the rest of the page*/
z-index: 99;
background: white;
border: none;
cursor: pointer;
top: 1rem;
right: 1rem;
}
.menu {
position: fixed;
/* give the menu a larger z-index than the ham link
to put the menu above it */
z-index: 100;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100vh;
/* basic menu styling*/
list-style: none;
background: black;
display: flex;
flex-direction: column;
/* animate slide up/down */
transform: translateY(-100%);
transition: transform 0.2s ease;
}
.close {
position: absolute;
border: none;
color: white;
cursor: pointer;
top: 1rem;
right: 1rem;
}
The menu is hidden by default with transform: translateY(-100%);. Translating -100% on the Y axis moves it 100% up above the screen.
By adding a transition transition: transform 0.2s; on transform we get a small slide in and out animation when the value of transform translateY changes.
And we reset the translation Y to 0 and show the menu on :target.
.menu:target {
/* show menu */
transform: translateY(0);
}
Thanks for reading π!
- Thanks Martin for telling me to animate transform instead of height to get GPU support.
Comments
Be the first one to comment.