DEV Community

Jacob Paris
Jacob Paris

Posted on

Hamburger Menu in Minimal Javascript

A few minutes ago I posted a tutorial on building a hamburger menu in pure CSS.
https://dev.to/jacobmparis/hamburger-menu-in-pure-css-mga

While it's a fun experiment and there's a lot to learn following the implementation of it, the truth is that in any production environment you're already going to be using javascript for a large portion of the site.

In that environment, you can get much cleaner code by driving the menu animation with javascript rather than relying on a checkbox and CSS sibling selectors.

https://codepen.io/anon/pen/YbKjxo

<button id="sidebar__trigger" class="sidebar__button">CLOSE</button>

<ul id="sidebar" class="sidebar">
    <li>Home Page</li>
    <li>Example 1</li>
    <li>Example 2</li>
    <li>Example 3</li>
    <ul>
        <li>Example 1</li>
        <li>Example 2</li>
        <li>Example 3</li>
    </ul>
    <li>Example 1</li>
    <li>Example 2</li>
    <li>Example 3</li>
</ul>

Enter fullscreen mode Exit fullscreen mode

We need a basic button with an ID so we can reference it in javascript, and a sidebar with an ID for the same reason.

.sidebar {
  background: #333;
  color: white;
  max-width: 200px;
  transition: transform 0.5s;

  &.isClosed {
    transform: translateX(-100%);
  }

  &__button {
    width: 300px;
    border: 1px solid #ddf;
    padding: 1rem;
    border-radius: 0.25rem;
  }
}
Enter fullscreen mode Exit fullscreen mode

Here the styles are all written in SCSS so we can take advantage of nesting. This saves a lot of repeated code, but requires that we precompile the CSS before serving it to the browser.

The & refers to the parent selector, so once this compiles out the .isClosed class will look like this:

.sidebar.isClosed {
  transform: translateX(-100%);
}
Enter fullscreen mode Exit fullscreen mode

This class translates the sidebar by its width to the left. Add the class, sidebar hides. remove the class, sidebar appears. Simple!

const sidebar = document.getElementById("sidebar");
const sidebarTrigger = document.getElementById("sidebar__trigger"); 
Enter fullscreen mode Exit fullscreen mode

Our first step is to select both of our elements so we can use them in our Javascript.

sidebarTrigger.addEventListener('click', () => {
    if(sidebar.classList.contains('isClosed')) {
        sidebar.classList.remove('isClosed');
        sidebarTrigger.innerText = "CLOSE";
    } else {
        sidebar.classList.add('isClosed');
        sidebarTrigger.innerText = "OPEN";
    }
})
Enter fullscreen mode Exit fullscreen mode

Here we add an event listener for the click event. Every time we click on the sidebarTrigger, the function we specify here will run.

If the sidebar has the .isClosed class, remove it and change the button text to CLOSE. Otherwise, add it and change the button text to OPEN.

And that's it! CSS handles all the animation and all the javascript has to do is toggle a class.

https://codepen.io/anon/pen/YbKjxo

Top comments (2)

Collapse
 
iamschulz profile image
Daniel Schulz • Edited

If you (ab)use a checkbox you can do this without any JS at all.

:checked ~ .sidebar__trigger {
    // styles for opened hamburger icon
}

:checked ~ sidebar {
    // styles for opened off canvas menu
}

To change the button text you could use the content property on the hamburger icon.

a rough implementation:

This brings the disadvantages of not using semantic HTML, however.

edit: nevermind, i just saw what you did there dev.to/jacobmparis/hamburger-menu-... :)

Collapse
 
jacobmparis profile image
Jacob Paris • Edited

If we didn't care about updating the button text on each click, we could replace the event listener with the much simpler

sidebarTrigger.addEventListener('click', () => {
    sidebar.classList.toggle('isClosed');
});

But we do, so we can't 😥