Responsive Menu with Dropdown Elements

323 views Asked by At

Mostly I'm copying the demo code from the PureCSS "docs" for implementing their dropdown menu.

I have created a CodePen, and will share code here as well.

The problem is that in the vertical version, the submenu items are not being revealed on hover or on click.

I am presuming this is by design and am not sure if it is expected that additional JavaScript (example) should be composed to enable reveal on click for touch devices and the like.

What I have is:

HTML:

<h1>PureCSS.io Responsive Nav Test</h1>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/build/grids-responsive-min.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/build/pure-min.css" integrity="sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin="anonymous">
<a href="#" class="custom-toggle" id="toggle"><s class="bar"></s><s class="bar"></s><s class="bar"></s></a>
 <nav class="custom-wrapper pure-menu custom-restricted-width pure-u-1" id="menu">
    <div class="pure-menu pure-menu-horizontal custom-can-transform">
      <ul id="menu-header-nav-menu" class="pure-menu-list">
        <li class="pure-menu-item">
           <a class="pure-menu-link" class='pure-menu-link' href="#">One</a>
        </li>
        <li class="pure-menu-item">
           <a class="pure-menu-link" class='pure-menu-link' href="#">Two</a>
         </li>
        <li class="pure-menu-item">
          <a class="pure-menu-link" class='pure-menu-link' href="#">Three</a>
        </li>
        <li class="pure-menu-item pure-menu-has-children pure-menu-allow-hover">
          <a class="pure-menu-link" class='pure-menu-link' href="#">Parent</a>
          <ul class="pure-menu-children">
              <li class="pure-menu-item">
              <a class="pure-menu-link" class='pure-menu-link' href="#">Child One</a>
             </li>
               <li class="pure-menu-item">
               <a class="pure-menu-link" class='pure-menu-link' href="#">Child Two</a>
             </li>
            </ul>
          </li>
        </ul>
    </div>
 </nav>

CSS:

  .site-header {
      position: relative;
  }

  .custom-wrapper {
      margin-bottom: 1em;
      -webkit-font-smoothing: antialiased;
      height: 2.1em;
      overflow: hidden;
      -webkit-transition: height 0.5s;
      -moz-transition: height 0.5s;
      -ms-transition: height 0.5s;
      transition: height 0.5s;
  }

  .custom-wrapper.open {
      height: 14em;
  }

  .custom-wrapper {
      height: 0;
  }

  .custom-toggle {
      width: 34px;
      height: 34px;
      position: absolute;
      top: 0;
      right: 0;
      display: none;
  }

  .custom-toggle {
      display: block;
  }

  .custom-toggle .bar {
      background-color: #777;
      display: block;
      width: 20px;
      height: 2px;
      border-radius: 100px;
      position: absolute;
      top: 18px;
      right: 7px;
      -webkit-transition: all 0.5s;
      -moz-transition: all 0.5s;
      -ms-transition: all 0.5s;
      transition: all 0.5s;
  }

  .custom-toggle .bar:first-child {
      -webkit-transform: translateY(-6px);
      -moz-transform: translateY(-6px);
      -ms-transform: translateY(-6px);
      transform: translateY(-6px);
  }

  .custom-toggle .bar:last-child {
      -webkit-transform: translateY(+6px);
      -moz-transform: translateY(+6px);
      -ms-transform: translateY(+6px);
      transform: translateY(+6px);
  }

  .custom-toggle.x .bar:last-child {
      display: none;
  }

  .custom-toggle.x .bar {
      -webkit-transform: rotate(45deg);
      -moz-transform: rotate(45deg);
      -ms-transform: rotate(45deg);
      transform: rotate(45deg);
  }

  .custom-toggle.x .bar:first-child {
      -webkit-transform: rotate(-45deg);
      -moz-transform: rotate(-45deg);
      -ms-transform: rotate(-45deg);
      transform: rotate(-45deg);
  }

  @media (min-width: 47.999em) {
    .custom-toggle {
        display: none;
    }

    .custom-wrapper {
      height: 3.2em;
      overflow: visible;
    }

    .pure-menu-children .pure-menu-item {
      background-color: #999;
    }
  }

Javascript:

(function (window, document) {
  var menu = document.getElementById('menu'),
      WINDOW_CHANGE_EVENT = ('onorientationchange' in window) ? 'orientationchange':'resize';

  function toggleHorizontal() {
      [].forEach.call(
          document.getElementById('menu').querySelectorAll('.custom-can-transform'),
          function(el){
              el.classList.toggle('pure-menu-horizontal');
          }
      );
  };

  function toggleMenu() {
      // set timeout so that the panel has a chance to roll up
      // before the menu switches states
      if (menu.classList.contains('open')) {
          setTimeout(toggleHorizontal, 500);
      }
      else {
          toggleHorizontal();
      }
      menu.classList.toggle('open');
      document.getElementById('toggle').classList.toggle('x');
  };

  function closeMenu() {
      if (menu.classList.contains('open')) {
          toggleMenu();
      }
  }

  document.getElementById('toggle').addEventListener('click', function (e) {
      toggleMenu();
      e.preventDefault();
  });

  window.addEventListener(WINDOW_CHANGE_EVENT, closeMenu);
})(this, this.document);

Am I correctly presuming that I need to handle the mobile subnav with additional script?

1

There are 1 answers

0
MikeiLL On BEST ANSWER

What was happening is that the "children" were off-page.

I'm not sure why it was required to modify the basic yui-pure-css mark-up, but to make this work in this case, I modified the following two items for the small screen sizes:

.pure-menu-has-children {
  position: relative;
}

.pure-menu-children {
    left: 3em;
    top: 2em;
}

The .pure-menu-children ul has position: absolute, but I'm not sure what it's relative parent is. Maybe it's the ul. At any rate, making it's relative parent the .pure-menu-has-children li facilitates it being displayed in relation to the parent list item.

I'm using a mobile first approach, so then for the media query for the larger viewports it can be restored to the framework defaults:

.pure-menu-children {
    left: 100%;
    top: 0;
}

However I think I prefer it as it is on the smaller devices. Here's an updated Pen.

Not completely happy. Maybe the vertical menu doesn't need to be quite so wide. I'm also, in this case, finding the need to add to .pure-menu-link a text-align: left, because the child item still seems to be aligning based on a full-width item.