这是一款效果很酷又简单实用的 jQueryCSS3 二级下拉菜单特效,该特效在点击触发按钮后,二级下拉菜单会向下滑动覆盖原来的主菜单,关闭后二级下拉菜单又向上滑动回去,二级菜单不占用多余的空间。

这个菜单插件是替代标准的二级下拉菜单的好方法,特别是在你想显示更多的二级子菜单的时候。另外,你可以十分容易的自定义二级下拉菜单的样式,多添加一个搜索框或登录注册表单等等。

HTML结构

该二级下拉菜单的HTML结构有两个主要部分:使用<header>元素来包裹导航菜单,使用<main>元素来放置页面的内容。

主导航菜单由两个嵌套的无序列表组成,包裹在一个<nav>元素中:

<header>
  <div class="cd-logo"><a href="#0"><img src="img/cd-logo.svg" alt="Logo"></a></div>
 
  <nav class="cd-main-nav-wrapper">
    <ul class="cd-main-nav">
      <li><a href="#0">About</a></li>
      <!-- other list items here -->
      <li>
        <a href="#0" class="cd-subnav-trigger"><span>Categories</span></a>
 
        <ul>
          <li class="go-back"><a href="#0">Menu</a></li>
          <li><a href="#0">Category 1</a></li>
          <!-- other list items here -->
        </ul>
      </li>
    </ul>
  </nav> 
  
  <a href="#0" class="cd-nav-trigger">Menu<span></span></a>
</header>
 
<main class="cd-main-content">
  <!-- main content here -->
</main>                
                

CSS样式

在小屏幕设备上,主导航菜单位于屏幕的右侧,默认是隐藏的。当用户点击了导航按钮,<main>元素和<header>元素会从右向左滑动出来(为其应用nav-is-visible class)。

当用户点击.cd-subnav-trigger(一个导航小箭头图标)按钮,二级菜单会从右向左滑动出来覆盖主菜单。

header.nav-is-visible {
  transform: translateX(-260px);
}
.cd-main-content.nav-is-visible {
  transform: translateX(-260px);
}
.cd-main-nav {
  position: fixed;
  top: 0;
  right: 0;
  width: 260px;
  visibility: hidden;
}
.cd-main-nav.nav-is-visible {
  visibility: visible;
}
.cd-main-nav li ul {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  transform: translateX(260px);
}
.cd-main-nav.moves-out > li > a {
  /* push the navigation items to the left - and lower down opacity - when secondary nav slides in */
  transform: translateX(-100%);
  opacity: 0;
}
.cd-main-nav.moves-out > li > ul {
  /* reveal secondary nav */
  transform: translateX(0);
}                  
                

在桌面设备上(分辨率大于1024px),二级菜单位于header的上部(默认隐藏),当点击导航按钮后会从上往下滑动下来,覆盖主菜单。可以为.cd-logo(网站logo)和.cd-subnav-trigger(二级菜单触发按钮)设置一个较高的z-index,这样可以使它们显示在二级菜单之上。

另外,可以为二级菜单设置和.cd-main-nav(主菜单)相同的padding,使它们尺寸相同,还可以在列表的最后插入一个.placeholder元素来制作和.cd-subnav-trigger(二级菜单触发按钮)相同的空间大小。

@media only screen and (min-width: 1024px) {
  .cd-main-nav {
    height: 80px;
    /* padding left = logo size + logo left position*/
    padding: 0 5% 0 calc(5% + 124px);
    text-align: right;
  }
  .cd-main-nav li ul {
    height: 80px;
    background-color: #7e4d7e;
    /* padding left = logo size + logo left position*/
    padding: 0 5% 0 calc(5% + 124px);
    transform: translateY(-80px);
    transition: transform 0.3s 0.2s;
  }
  .cd-main-nav li ul li {
    opacity: 0;
    transform: translateY(-20px);
    transition: transform 0.3s 0s, opacity 0.3s 0s;
  }
  .cd-main-nav .placeholder {
    /* never visible or clickable- it is used to take up the same space as the .cd-subnav-trigger */
    display: block;
    visibility: hidden;
    opacity: 0;
    pointer-event: none;
  }
  .cd-main-nav.moves-out > li > ul {
    transition: transform 0.3s;
    transform: translateY(0);
  }
  .cd-main-nav.moves-out > li ul li {
    opacity: 1;
    transform: translateY(0);
    transition: transform 0.3s 0.2s, opacity 0.3s 0.2s;
  }
}                  
                

JAVASCRIPT

插件中使用jQuery来为元素添加和移除相应的class。

唯一值得注意的事情是在HTML结构中单行菜单要位于<header>中。在移动设备上,我们希望导航菜单位于屏幕的侧边上,默认隐藏。这里使用jQuery来在移动设备上将导航菜单移出header之外。

jQuery(document).ready(function($){
  //move nav element position according to window width
  moveNavigation();
  $(window).on('resize', function(){
    (!window.requestAnimationFrame) ? setTimeout(moveNavigation, 300) : window.requestAnimationFrame(moveNavigation);
  });

  //mobile version - open/close navigation
  $('.cd-nav-trigger').on('click', function(event){
    event.preventDefault();
    if($('header').hasClass('nav-is-visible')) $('.moves-out').removeClass('moves-out');
    
    $('header').toggleClass('nav-is-visible');
    $('.cd-main-nav').toggleClass('nav-is-visible');
    $('.cd-main-content').toggleClass('nav-is-visible');
  });

  //mobile version - go back to main navigation
  $('.go-back').on('click', function(event){
    event.preventDefault();
    $('.cd-main-nav').removeClass('moves-out');
  });

  //open sub-navigation
  $('.cd-subnav-trigger').on('click', function(event){
    event.preventDefault();
    $('.cd-main-nav').toggleClass('moves-out');
  });

  function moveNavigation(){
    var navigation = $('.cd-main-nav-wrapper');
      var screenSize = checkWindowWidth();
        if ( screenSize ) {
          //desktop screen - insert navigation inside header element
      navigation.detach();
      navigation.insertBefore('.cd-nav-trigger');
    } else {
      //mobile screen - insert navigation after .cd-main-content element
      navigation.detach();
      navigation.insertAfter('.cd-main-content');
    }
  }

  function checkWindowWidth() {
    var mq = window.getComputedStyle(document.querySelector('header'), '::before').getPropertyValue('content').replace(/"/g, '');
    return ( mq == 'mobile' ) ? false : true;
  }
});