Web Development

Clean Application — Hamburger Menu

The third part of a step-by-step tutorial to build a clean, lightweight, and extremely fast web application.


Photo by emy on Unsplash

This is the third part of a step-by-step tutorial to build a clean, lightweight, and extremely fast web application together without any fast-food frameworks. Please check out the previous part if you haven’t already:

The hamburger menu button, as the name suggests due to its appearance as a pixel hamburger, is a button that is usually positioned at the top corner of a graphical user interface (GUI). Its basic functionality is in toggling a menu or providing a navigation bar by being collapsed behind the menu button or displayed on the screen. Further detailed explanation about this type of button can be found on Wikipedia.

+--------------------------------+
│         HEADER AREA         ☰ │
+--------------------------------+
│                                │
│                                │
│             CONTENT            │
│              AREA              │
│                                │
+--------------------------------+
│          FOOTER AREA           │
+--------------------------------+

This trigram symbol (☰), at the top right corner of the above diagram, can be added using the below Unicode symbol:

:after {
  content:'\2630';
}

For our exercise, we will try to create a more smooth and animated menu button for a better user experience.

Creating a Simple Navigation Menu

As done before, for the purpose of simplicity, we will reuse our earlier application by creating the 03-nav folder and copying the contents of 02-positions into this newly created folder.

Our directory structure will look like the following:

03-nav
├── styles
│   ├── app.css
│   ├── flex.css
│   ├── nav.css
│   └── theme.css
└── index.html

First of all, let us update the <header> by adding our navigation menu to the index.html page:

<header>
  <h1>Header</h1>
  <nav id="nav">
    <input type="checkbox" aria-label="Toggle menu">
    <div class="hamburger"><span></span></div>
    <ul class="menu">
      <li><a href="./index.html">Home</a></li>
      <li><a href="./index.html">About</a></li>
      <li><a href="./index.html">Contact</a></li>
    </ul>
  </nav>
</header>

Next, we can create nav.css file. Behold! a lengthy coding awaits ahead:

nav {
  display: block;
  float: right;
  left: -1em;
  padding-top: .2em;
  position: absolute;
  user-select: none;
  width: 100%;
  z-index: 1;
  -webkit-user-select: none;
}

nav input,
nav .hamburger {
  height: 32px;
  position: absolute;
  right: 0;
  width: 40px;
}

nav input {
  display: block;
  opacity: 0;
  z-index: 2;
  -webkit-touch-callout: none;
}

nav .hamburger span,
nav .hamburger span:before,
nav .hamburger span:after {
  border-radius: 4px;
  height: 2px;
  position: absolute;
  transition: transform .15s ease;
  width: 35px;
}

nav .hamburger span {
  display: block;
  margin-top: 8px;
  transition-duration: .4s;
  transition-timing-function: cubic-bezier(.68, -.55, 0.265, 1.55);
}

nav .hamburger span:before,
nav .hamburger span:after {
  content: "";
  display: block;
}

nav .hamburger span:before {
  top: 10px;
  transition: opacity .15s .4s ease;
}

nav .hamburger span:after {
  bottom: -10px;
  top: 20px;
  transition: transform .4s cubic-bezier(.68, -.55, .265, 1.55);
}

nav ul {
  bottom: 0;
  left: 0;
  list-style-type: none;
  opacity: 0;
  padding: 2.5em 1em;
  position: fixed;
  right: 0;
  top: 4em;
  transform-origin: 0% 0%;
  transform: translate(0, -200%);
  transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0), opacity 0.5s ease-out;
  text-align: right;
  width: 100%;
  -webkit-font-smoothing: antialiased;
  z-index: 99;
}

nav input:checked ~ ul {
  opacity: .95;
  transform: none;
  z-index: 99;
}

nav input:checked ~ .hamburger span {
  transform: translate3d(0, 10px, 0) rotate(135deg);
  transition-delay: 0.1s;
}

nav input:checked ~ .hamburger span:before {
  opacity: 0;
  transition-delay: 0s;
}

nav input:checked ~ .hamburger span:after {
  transform: translate3d(0, -20px, 0) rotate(-270deg);
  transition-delay: .1s;
}

nav .menu a {
  display: inline-block;
  margin: 1em 0 0;
  padding: 1em 1em .8em;
  text-decoration: none;
  text-transform: uppercase;
}

nav .menu .active,
nav .menu :active {
  border-radius: 3px;
}

@media only screen and (min-width: 768px) {
  nav .hamburger {display: none;}
  nav, nav ul  {padding: 0; position: static; margin: 0; width: auto;}
  nav ul {opacity: 1; margin-top: -1em; transform: none; transition: none;}
  nav li {display: inline-block;}
  nav .menu .active {margin: 1em;}
}

Improving the Presentation

For the purpose of improving the way it appears, we need to update theme.css file so that the menu button is presented smoothly:

nav ul,
nav a {
  background-color: Indigo;
  color: White;
}

nav .menu a.active,
nav .menu a:active,
nav .menu a:hover {
  background-color: DarkMagenta;
}

nav .hamburger span,
nav .hamburger span::before,
nav .hamburger span::after {
  background-color: White;
}

Testing the Result

Note: Do not forget to link the nav.css file to the index.html page:

<link href="./styles/nav.css" rel="stylesheet">

Now we can open the index.html page using our browser. The page can be resized (as we had done previously) or emulated for mobile devices using Chrome Dev Tools: