hoangweb
3/8/2018 - 3:34 AM

multi level dropdown menu

multi level dropdown menu: vertical & horizontal dropdown menu

(function(){
    function $(selector, context){
        context = context || document;
        return context["querySelectorAll"](selector);
    }

    function forEach(collection, iterator){
        for(var key in Object.keys(collection)){
            iterator(collection[key]);
        }
    }

    function showMenu(menu){
        var menu = this;
        var ul = $("ul", menu)[0];

        if(!ul || ul.classList.contains("-visible")) return;

        menu.classList.add("-active");
        ul.classList.add("-animating");
        ul.classList.add("-visible");
        setTimeout(function(){
            ul.classList.remove("-animating")
        }, 25);
    }

    function hideMenu(menu){
        var menu = this;
        var ul = $("ul", menu)[0];

        if(!ul || !ul.classList.contains("-visible")) return;

        menu.classList.remove("-active");
        ul.classList.add("-animating");
        setTimeout(function(){
            ul.classList.remove("-visible");
            ul.classList.remove("-animating");
        }, 300);
    }

    function hideAllInactiveMenus(menu){
        var menu = this;
        forEach(
            $("li.-hasSubmenu.-active:not(:hover)", menu.parent),
            function(e){
                e.hideMenu && e.hideMenu();
            }
        );
    }

    window.addEventListener("load", function(){
        forEach($(".Menu li.-hasSubmenu"), function(e){
            e.showMenu = showMenu;
            e.hideMenu = hideMenu;
        });

        forEach($(".Menu > li.-hasSubmenu"), function(e){
            e.addEventListener("mouseover", showMenu);
        });

        forEach($(".Menu > li.-hasSubmenu li"), function(e){
            e.addEventListener("mouseenter", hideAllInactiveMenus);
        });

        forEach($(".Menu > li.-hasSubmenu li.-hasSubmenu"), function(e){
            e.addEventListener("mouseenter", showMenu);
        });

        document.addEventListener("click", hideAllInactiveMenus);
    });
})();
/*
Naming convention:
Block
element
-modifier
*/

.Menu {
    display: none;
    position: relative;
}
    /* Three basic menu layouts */
    /* This also enforces that menu is a ul, and that
     * layout modifier is specified
     */
    ul.Menu.-horizontal,
    ul.Menu.-vertical {
        display: inline-block;
    }
    ul.Menu.-floating {
        display: block;
        position: absolute;
    }

    /* Menu and menu-item layout */
    .Menu,
    .Menu li,
    .Menu li > ul {
        list-style: none;
        padding: 0px;
        margin: 0px;
    }
    .Menu li {
        display: block;
        position: relative;
        white-space: nowrap;
        word-break: keep-all;
    }
    .Menu.-horizontal > li {
        display: inline-block;
        float: left;
    }
    .Menu li > * {
        display: block;
        position: relative;
    }
    .Menu li > ul {
        position: absolute;
        min-width: 100%;
        top: 0px;
        left: 100%;
    }
    .Menu.-horizontal.-alignRight li > ul {
        left: auto;
        right: 100%;
    }
    .Menu.-horizontal.-alignRight > li > ul {
        right: 0px;
    }
    .Menu.-horizontal > li > ul {
        top: auto;
        left: auto;
    }

    /* Menu behaviour */
    .Menu li > ul,
    .Menu.-floating {
        display: none;
    }
    .Menu li > ul.-visible,
    ul.Menu.-floating.-visible {
        display: block;
    }

    /* Menu animation */
    .Menu li > ul,
    .Menu.-horizontal.-alignRight li > ul,
    .Menu.-floating {
        opacity: 1;
        transform: scale(1) translateY(0px);
        transform-origin: left top;
    }
    .Menu.-alignRight li > ul,
    .Menu.-floating.-alignRight {
        transform-origin: right top;
    }
    .Menu li > ul.-animating,
    .Menu.-floating.-animating {
        opacity: 0 !important;
        transform: scale(0.96) translateX(-16px);
    }
    .Menu li > ul.-animating {
        z-index: -1 !important;
    }
    .Menu.-horizontal > li > ul.-animating {
        transform: scale(0.96) translateY(-16px);
    }
    .Menu.-alignRight li > ul.-animating,
    .Menu.-floating.-alignRight.-animating {
        transform: scale(0.96) translateX(16px);
    }
    .Menu.-horizontal.-alignRight > li > ul.-animating {
        transform: scale(0.96) translateY(-16px);
    }

    /* Menu item icons */
    .Menu *[data-icon]:before {
        position: absolute;
        left: 0px;
        top: 0px;
        bottom: 0px;
        margin: auto 0px;
    }
    .Menu .Icon,
    .Menu *[data-icon]:before {
        line-height: inherit;
    }
    .Menu .Icon {
        padding: 0px;
    }
    .Menu *:empty[data-icon] {
        padding-left: 0px !important;
        padding-right: 0px !important;
    }

    /* Submenu chevrons */
    .Menu li.-hasSubmenu > a:after {
        display: block;
        position: absolute;

        width: 8px;
        height: 8px;
        right: 8px;
        bottom: 0px;
        top: 0px;
        margin: auto 0px;

        transform: rotate(45deg);
        border-width: 1px;
        border-color: black;
        border-style: solid solid none none;

        content: "";
    }
    .Menu.-horizontal > li.-hasSubmenu > a:after {
        width: 4px;
        height: 4px;
        bottom: 4px;
        top: auto;
        left: 0px;
        right: 0px;
        margin: 0px auto;

        border-style: none solid solid none;
    }
    .Menu li.-hasSubmenu.-noChevron > a:after {
        display: none;
    }

/*
** Configurable values
*/
    /* Height of navbar, and menu items */
    /* All of these must be of equal value */
    .Menu {
        line-height: 40px;
    }
    .Menu.-horizontal,
    .Menu li,
    .Menu li > :first-child {
        height: 40px;
    }
    .Menu *[data-icon]:before,
    .Menu .Icon {
        width: 40px;
        height: 40px;
    }
    .Menu *[data-icon] {
        min-width: 40px;
        min-height: 40px;
        padding-left: 40px;
    }

    /* Default font settings for menu */
    .Menu {
        font-family: Arial, Helvetica, Sans;
        font-size: 16px;
    }

    /* Icon font sizes */
    .Menu *[data-icon]:before,
    .Menu .Icon {
        font-size: 24px;
    }
    /* For submenus */
    .Menu > li ul .Icon,
    .Menu.-floating .Icon,
    .Menu > li ul *[data-icon]:before,
    .Menu.-floating *[data-icon]:before,
    {
        font-size: 18px;
    }

    /* Colouring of menus */
    /* Foreground */
    .Menu,
    .Menu li.-hasSubmenu > a:after {
        color: black;
        border-color: black; /* chevron colour */
    }
    /* Background */
    .Menu ul,
    .Menu.-floating {
        background: white;
    }

    /* Padding for each menu item */
    .Menu li > * {
        padding: 0px 12px;
    }
    /* Indent of chevron */
    .Menu li li.-hasSubmenu > a:after,
    .Menu:not(.-horizontal) > li.-hasSubmenu > a:after {
        right: 12px;
    }
    .Menu li li.-hasSubmenu > a,
    .Menu:not(.-horizontal) > li.-hasSubmenu > a {
        padding-right: 28px;
    }

    /* Minimum width of dropdown menus */
    .Menu.-horizontal li > ul,
    .Menu.-floating {
        min-width: 200px;
    }

    /* Animation speed of dropdown menus */
    .Menu li > ul,
    .Menu.-floating {
        transition: width 0.1s, height 0.1s, transform 0.1s, opacity 0.1s;
    }

    /* Styling of hyperlink text */
    .Menu li > a {
        text-decoration: none;
        color: inherit;
    }

    /* Animation speed of :hover shading */
    .Menu li > a:first-child {
        transition: background-color 0.2s;
    }

    /* Colour of :hover shading */
    .Menu li:hover > a:first-child,
    .Menu li.-active > a:first-child {
        background-color: rgba(0,0,0,0.1);
    }

/*
** End configurable values
*/
<!--
https://www.cssscript.com/multi-level-dropdown-menu-pure-javascript-tidy-menu/
-->
<link rel="stylesheet" href="menu.css">
<script src="menu.js"></script>

<!-- MENU HTML 
note:
- vertical: class="Menu -vertical"
- horizontal: class="Menu -horizontal"
-->
<ul class="Menu -horizontal">
  <li class="-hasSubmenu -noChevron"> <a href="#" data-icon="apps"></a>
    <ul>
      <li><a href="#">Bacon</a></li>
      <li><a href="#">Ipsum</a></li>
      <li><a href="#">Dolor</a></li>
      <li><a href="#">Amet</a></li>
    </ul>
  </li>
  <li class="-hasSubmenu"> <a href="#">Alpha</a>
    <ul>
      <li><a href="#">Bacon</a></li>
      <li><a href="#">Ipsum</a></li>
      <li class="-hasSubmenu"> <a href="#">Sub-menu</a>
        <ul>
          <li><a href="#">Bacon</a></li>
          <li><a href="#">Ipsum</a></li>
          <li><a href="#">Dolor</a></li>
          <li><a href="#">Amet</a></li>
        </ul>
      </li>
      <li><a href="#">Dolor</a></li>
      <li><a href="#">Amet</a></li>
      <li class="-hasSubmenu"> <a href="#">Another Sub-menu</a>
        <ul>
          <li><a href="#">Bacon</a></li>
          <li><a href="#">Ipsum</a></li>
          <li class="-hasSubmenu"> <a href="#">Sub-sub-menu!</a>
            <ul>
              <li><a href="#">Bacon</a></li>
              <li><a href="#">Ipsum</a></li>
              <li><a href="#">Dolor</a></li>
              <li><a href="#">Amet</a></li>
            </ul>
          </li>
          <li><a href="#">Dolor</a></li>
          <li><a href="#">Amet</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a href="#">Beta</a></li>
  <li class="-hasSubmenu"> <a href="#">Gamma</a>
    <ul>
      <li><a href="#" data-icon="">Ipsum</a></li>
      <li class="-hasSubmenu"> <a data-icon="cast" href="#">Dolorsssssssssssssssssssssssss</a>
        <ul>
          <li><a href="#">Bacon</a></li>
          <li><a href="#">Ipsum</a></li>
          <li><a href="#">Dolor</a></li>
          <li><a href="#">Amet</a></li>
        </ul>
      </li>
      <li><a href="#" data-icon="">Amet</a></li>
      <li><a href="#" data-icon="cake">Tail pork loin chicken</a></li>
      <li><a href="#" data-icon="">Bacon ipsum dolor amet pork loin rump filet mignon swine</a></li>
    </ul>
  </li>
  <li><a href="#">Delta</a></li>
  <li><a href="#">Epsilon</a></li>
</ul>