Recently, I had a junior colleague who had just started learning HTML and CSS asked me about how they can create a functional hamburger menu with only CSS. In my mind this will be easier to do using JavaScript but I haven’t been taught about how to do that with CSS. So, once I was asked, I had to figure out how to achieve the same using HTML and CSS only without JavaScript.
I found a way to do that and that is exactly what you will be learning in this CSS mini-project for beginners. To make it worth your time, you will find the application of various CSS concepts with explanations on how to use those concepts so you can easily implement them in your other projects with little to no help at all.
Here is the final output of this mini-project. You can begin to explore it or go through the tutorial before coming back to it.
If you prefer a detailed step by step video tutorial, then you can watch the video version of this project-based HTML and CSS tutorial:
CSS Concepts that this project covers
This mini-project covers a range of CSS concepts to create a functional hamburger menu using only HTML and CSS. Here are the concepts included:
- Selectors and Properties: Utilizing various CSS selectors to style elements specifically and apply CSS properties effectively.
- Class Selector: Using the class selector (.class) to style specific elements and groups of elements.
- Positioning: position: absolute; and position: relative; to place and align elements in the menu and the toggle button. Understanding how elements are positioned in relation to others and their parent elements.
- Display Property: Use of display: block; to structure the layout of the menu and its items.
- Dimensions: Setting width and height properties to define the size of elements.
- Box Model: Understanding and manipulating margin, padding, and border to achieve the desired spacing and size for elements.
- Overflow: Utilizing overflow-x: hidden; to prevent horizontal scrolling and ensure layout does not break.
- CSS Transitions: Using transition properties to animate changes in properties smoothly over a specified duration.
- Transformations: Employing transform to rotate and translate elements, especially for animating the hamburger icon to a close (X) icon.
- Visibility and Opacity: Controlling the visibility of elements with opacity and display properties.
- Pseudo-Classes: Using :checked to style elements differently based on the state of the checkbox.
- Sibling Combinator (~): Using the general sibling combinator to style siblings of an element conditionally, particularly for changing the appearance of the menu icon when the menu is toggled.
How is it going to work?
For this mini-project, you will develop a simple hamburger menu which will open to the left side of the screen.
There will be a hamburger icon (with three horizontal bars) on the left hand side and when you click on it, one of the bars will be hidden and the remaining two will rotate to cross each other to create a cancel icon (X).
Also, the menu items will be displayed as a sidebar that will be shown or hidden depending on whether the hamburger icon has been clicked or not.
Writing the HTML Code
Before writing the HTML code, you need to appreciate the exact layout and also the CSS trick that will enable us to imitate the on click event which would have ideally been implemented using JavaScript. The CSS trick for this involves using a hidden checkbox and making the cursor into a pointer so it looks clickable.
The checkbox will be hidden but you will have the hamburger icon (which you can achieve with three <span> elements) adjacent to it so it feels like it was the hamburger icon that is being clicked.
To begin, go ahead and create your `index.html` file and write the HTML code for the menu. You can use the code below as a guide but focus on understanding the reason why each element is used the way it is used.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hamburger Menu</title> <link rel="stylesheet" href="styles.css"> </head> <body> <nav> <div class="menu__toggle"> <input type="checkbox" /> <!-- spans for hamburger icon --> <span></span> <span></span> <span></span> <ul class="menu__links"> <a href="#"><li>Home</li></a> <a href="#"><li>Services</li></a> <a href="#"><li>Products</li></a> <a href="#"><li>Pricing</li></a> <a href="#"><li>About</li></a> </ul> </div> </nav> </body> </html>
Understanding the HTML Structure
In the HTML structure provided above, you have created the basic skeleton for the hamburger menu. Here’s a quick rundown of each part:
- <nav>: This is the container for your navigation menu. It’s a semantic HTML element that defines a section of navigation links.
- .menu__toggle: This div acts as the wrapper for the toggleable elements of the menu — the checkbox and the spans for the hamburger icon.
- <input type=”checkbox” />: This is the hidden checkbox that acts as the actual clickable area. It will control the visibility of the menu and the transformation of the hamburger icon into a cancel icon.
- Spans for the hamburger icon: These three span elements will be styled to look like the lines of a hamburger icon. They will also change when the menu is active to form a ‘X’ shape.
- .menu__links: This unordered list will contain your navigation links. These links will be hidden or shown depending on the state of the checkbox.
Now, let’s move on to the CSS to bring this structure to life.
Writing the CSS Code
You may want to reset the default browser styles. This involves margin, padding, font-family, box-sizing, text-decoration, etc.
*{ margin: 0; padding: 0; box-sizing: border-box; text-decoration: none; } body { font-family: Arial, sans-serif; overflow-x: hidden; background-color: rgb(41, 56, 71); }
Here is an explanation to the code above:
CSS Reset:
- * { … }: This is a universal selector in CSS. It targets all elements on your webpage. The styles inside this block will apply to every element.
- margin: 0;: This sets the margin (space outside the border) of all elements to 0, removing any default space added by the browser.
- padding: 0;: This sets the padding (space inside the border) of all elements to 0, removing any default space inside elements.
- box-sizing: border-box;: This makes the element’s total width and height include any padding and border, but not margin. It’s a way to ensure elements size up as you expect them to.
- text-decoration: none;: This removes any default text decorations, like underlines on links.
Body Styling:
- body { … }: This block targets the <body> element, which wraps all the content on your webpage.
- font-family: Arial, sans-serif;: This sets the default font for your webpage to Arial, a common, sans-serif font. If Arial is not available, it will fall back to any available sans-serif font.
- overflow-x: hidden;: Prevents horizontal scrolling on the webpage by hiding content that overflows the viewport’s width. This ensures the page only scrolls vertically.
- background-color: rgb(41, 56, 71);: This sets a dark background color (a shade of dark blue) for the body.
- color: #cdcdcd;: Sets the default text color to a light gray shade (#cdcdcd). This color is chosen to contrast well against the dark background, ensuring that all text is legible and stands out for easy reading.
This is what your work would look like:
The next step will be to begin styling the navigation. Start by targeting the div (.menu__toggle) within the nav element. To ensure that you have some space around the menu and display’s neatly, you will need to explicitly position it. You can achieve this by displaying it as a block element and then setting the position to relative. Finally, use top and left properties to set it to the specific position you want. An example is shown below:
.menu__toggle { display: block; position: relative; top: 50px; left: 50px; z-index: 1; }
As you can see, the menu has been moved a bit with some space both from top and left sides.
The next thing will be to hide the checkbox and also make it clickable as discussed earlier. The code below can help you achieve that:
.menu__toggle input[type="checkbox"] { display: block; width: 40px; height: 32px; position: absolute; top: -7px; left: -5px; cursor: pointer; opacity: 0; z-index: 2; }
In the above code, the checkbox is being displayed as a block-level element and a width and height which will be similar to what you may be using for the hamburger icon is set for it. It is also positioned absolute so you can manually determine where to put it. The goal is to position it on top of the hamburger icon and then hide it. So, when someone clicks on the hamburger icon, they would technically be clicking this checkbox (except that this will be hidden). The z-index is therefore set to 2 and you would have to make sure that that for the hamburger icon will be less than 2 so that the icon will lie below the invisible checkbox. The exact positioning (top and left values) is to align the invisible checkbox with the custom designed toggle area, ensuring the clickable area is intuitive for users.
The end result will be like the screen below and as you can see the checkbox isn’t visible. This is because the Opacity property was set to zero (0).
If you remove the opacity, you will end up with something like this which shows that the checkbox has increased in size and has been positioned on top of the menu items.
Proceed to style the hamburger icon. As mentioned earlier, you will be doing that using the three span elements you created in the HTML code. Each span will be displayed as a block-level element, given a specific width (preferably slightly smaller than the width of the invisible checkbox) and height.
Also, set some margin bottom so as to make enough space between the individual lines of the hamburger icon. Set a visible color as the background color so it stands out. Remember to set the z-index to a value less than 2 so that it will lie below the hamburger menu.
.menu__toggle span { display: block; width: 33px; height: 4px; background-color: #cdcdcd; margin-bottom: 5px; position: relative; z-index: 1; }
NB: `position: relative;`: This sets the position of the span elements to relative. While this property doesn’t do much on its own in this context, it’s often used when you need to position pseudo-elements or when you’ll adjust the positioning of the spans later in response to some interaction (like turning the hamburger icon into an “X” icon).
Well done! Your hamburger icon is ready now.
Time to build in some form of animations. You can use transitions and transform to create some sort of animation which involves change from the default hamburger icon to the “X” icon when clicked and vice versa.
To achieve that, you will need to use the pseudo element `:checked` on the checkbox input element. Once the hidden checkbox is checked (ie: when a user clicks on the hamburger icon), then you rotate the spans which make up the hamburger icon. It is a bit tricky and to pull it off you may have to take each span at a time and style it appropriately. Remember that to form the “X” icon, you will need only two spans instead of the three that were used in the hamburger icon. Also, you will need one to be crossing the other.
You need to update the ruleset for the spans to include a transition property that will create a smooth animation for the transformations, background color changes and opacity changes (`transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0), background 0.5s cubic-bezier(0.77,0.2,0.05,1.0), opacity 0.55s ease;`).
.menu__toggle span { display: block; width: 33px; height: 4px; background-color: #cdcdcd; margin-bottom: 5px; position: relative; z-index: 1; transform-origin: 4px 0px; transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0), background 0.5s cubic-bezier(0.77,0.2,0.05,1.0), opacity 0.55s ease; }
For the purpose of this tutorial, a different background will be used for the menu items. This background will only show up when the hamburger menu is activated. At that point, you may also want to change the color of the hamburger icon so it remains visible.
.menu__toggle input:checked ~ span { opacity: 1; transform: rotate(45deg); background: #232323; }
This part targets all spans when the input (checkbox) is checked, indicating that the hamburger menu is activated.
- opacity: 1; ensures that the spans are fully visible. This is because the middle line in the hamburger icon will be hidden by setting opacity to zero when toggling.
- transform: rotate(45deg); rotates the spans 45 degrees, starting the transformation into an “X.”
- background: #232323; changes the color of the spans to a darker shade, possibly to indicate an active or clicked state.
Go on to target the middle line in the hamburger icon and hide it when the hamburger is activated by setting opacity to zero.
.menu__toggle input:checked ~ span:nth-last-child(3) { opacity: 0; }
This specifically targets the third-to-last child in the div which is a span (the middle line in the hamburger icon) when the checkbox is checked.
- opacity: 0; makes the middle line disappear, helping form the top and bottom lines into an “X” shape.
Finally, you can rotate the first line in the hamburger icon in the opposite direction so that it crosses that of the last one to form the “X” shape when the hamburger is activated.
.menu__toggle input:checked ~ span:nth-last-child(2) { transform: rotate(-45deg) ; }
The basic animation for the hamburger icon is ready now. You can now proceed to style the menu items and also add some animations to them.
.menu__links { position: absolute; width: 300px; height: 100vh; margin: -100px 0 0 -50px; padding: 125px 50px 50px 50px; background-color: #ededed; list-style: none; }
When you click on the hamburger icon, the “X” icon should now be more visible.
Since this menu is supposed to be visible only when the hamburger icon is activated, you need to hide it when it is not activated. To create a slide out effect, you can use `translate(-100%, 0)` as the value for the transform property and this moves the menu completely off the screen. To make the transition nice, add a transition property for the transformation.
.menu__links { position: absolute; width: 300px; height: 100vh; margin: -100px 0 0 -50px; padding: 125px 50px 50px 50px; background-color: #ededed; list-style: none; transform: translate(-100%, 0); transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0); }
Now, you can target the menu items with the help of the ul element when the hamburger has been activated (using the input:checked pseudoelement) and set the transform to none.
.menu__toggle input:checked ~ ul { transform: none; }
The major part is done now but you need to style the menu items well.
You can now target the <a> elements and the <li> elements style them to your liking. You can try with the example below:
.menu__links a { color: rgb(41, 56, 71); transition: color 0.3s ease; } .menu__links a:hover { color: orangered; } .menu__links li { padding: 10px 0; font-size: 22px; }
Here is the final output. The menu only shows up when you click on the hamburger icon.
As you can see, this was done with only HTML and CSS without using any JavaScript.
Congratulations on completing this mini-project. This is a feat worth celebrating. You can join the LearninBits community to stay in touch with the team and take advantage of the various training programs organized by the team. Click here to join the community: https://learninbits.com/telegram.