Search code examples
javascripthtmlcssmedia-queries

How to make a collapsible menu @media


How to make a collapsible navbar if the screen is smaller ? My code looks like this:

<header class="header">
  <a href="#" class="logo">
    <img src="images/logo.png" alt="">
  </a>
  <nav class="navbar">
    <div class="cart">
      <a href="index.html">Strona główna</a>
      <a href="shop.html">Sklep</a>
      <a href="cart.html">
      <ion-icon name="basket"></ion-icon>Koszyk<span>0 </span>
    </a>
    </div>
  </nav>
</header>


Solution

  • First, you will need to add the components that implement a disclosure pattern, i.e. the burger button.

    And don’t forget to provide a helpful alt Text for your logo, usually the name visible inside the Logo

    <header class="header">
    <a href="#" class="logo">
        <img src="images/logo.png" alt="ACME">
    </a>
    <nav class="navbar">
      <button class="navtoggle" aria-expanded="false" aria-label="Menu"><ion-icon name="menu-outline"></ion-icon></button>
      <div class="cart" class="cart--hidden">
      …
    

    If you don’t want to use a <button>, you’ll need to apply role=button and make sure that the element is focusable by means of keyboard as well, maybe by tabindex=0.

    Then, via CSS Media Queries you can control on which viewport sizes you want to allow users to toggle the menu open and closed.

    If you apply Mobile First coding, your basic CSS will be the smallest version, and then min-width queries add layouts for bigger screens. 900px is just an example, you might want to determine that breakpoint depending on the size of your menu.

    .cart--hidden { display: none; }
    
    @media screen and (min-width: 900px) {
      .navtoggle { display: none; }
      .cart--hidden { display: block };
    }
    

    Finally, you’ll need to bind to the click event to change the toggle-status in JavaScript.

    const toggle = document.querySelector('.navtoggle');
    const cart = document.querySelector('.cart');
    
    toggle.addEventListener('click', () => {
      if (toggle.ariaExpanded === "true") {
        toggle.ariaExpanded = "false";
        cart.classList.add('cart--hidden');
      } else {
        toggle.ariaExpanded = "true";
        cart.classList.remove('cart--hidden');
      }
    });
    .cart--hidden { display: none; }
    
    @media screen and (min-width: 900px) {
      .navtoggle { display: none; }
      .cart--hidden { display: block; }
    }
    <header class="header">
    <a href="#" class="logo">
        <img src="images/logo.png" alt="ACME">
    </a>
    <nav class="navbar">
        <button class="navtoggle" aria-expanded="false">Menu</button>
        <div class="cart cart--hidden">
            <a href="index.html">Strona główna</a>
            <a href="shop.html">Sklep</a>
            <a href="cart.html">
                <ion-icon name="basket"></ion-icon>Koszyk<span>0 </span>
            </a>
        </div>
    </nav>

    Beware again, that if you don’t use a <button> for the toggle, you will need to bind keydown handlers as well. Browsers do that by default for certain interactive elements.