A common mistake made when coding a hamburger menu.

Hamburger....

When coding a hamburger menu most developers or coders position the menu absolute, when in actual fact it should be the content that is positioned once the sidebar is opened. Instead of positioning the menu itself, simply position everything else that’s in the menu. Below is some example code, followed up with explanatory comments….

HTML

<html>
<head></head>
<body>
  <div class="sidebar">Hamburger menu links go here</div>
  <div class="main-content"><button class="hamburger-menu-icon" onClick="toggleSidebar()">🍔</button></div>
</body>
</html>

CSS

/* Arbitrary CSS variable values for explanatory purposes */
:root {
  --sidebar-width: 100px;
  --sidebar-bg-colour: blue;
}

.sidebar {
  display: none;
  position: relative;
  width: var(--sidebar-width);
}

@media (max-width: 767px) {
  html.sidebar-is-open .sidebar {
    display: block; 
     /* 
      The sidebar is just rendered in default position,
      as it appears in the document flow
     */
  }

  html.sidebar-is-open .main-content {
    position: fixed; 
    /* 
     It is the main content that is positioned. 
     This is the crux of the implementation. The rest is all sugar.

     Cons: the body will scroll to the top, losing your user's scroll position
    */

    /* prevents resizing from its original full-screen width */
    bottom: 0;
    left: 0;
    right: 0;
    top: 0;
    width: 100%; 

    overflow: hidden;
  }

  /* Optional enhancement: 
     make the overscroll on iPhone the same colour as the sidebar */
  html.sidebar-is-open body {
    background-color: var(--sidebar-bg-colour);
  }
  .sidebar {
    background-color: var(--sidebar-bg-colour);
  }
}

const documentElement = document.querySelector("html");
const contentElement = document.querySelector(".main-content");
const sidebarElement = document.querySelector(".sidebar");
const sidebarIsOpen = () => documentElement.classList.contains("sidebar-is-open");

const openSidebar = () => {
  /* How you trigger the change is up to you */
  documentElement.classList.add("sidebar-is-open");
};

const closeSidebar = () => {
  documentElement.classList.remove("sidebar-is-open");

  /* Sidebar is closed, so keeping event listener is just a waste of resources
     and source of bugs if openSidebar() is run again */
  contentElement.removeEventListener("click");
};

const toggleSidebar = () => {
  sidebarIsOpen() ? closeSidebar() : openSidebar();
};

Related posts