点击预览效果,实现该响应式下拉导航菜单并不复杂,只需要编写一些CSS3样式规则(主要是媒体查询+CSS3动画)和几行原生的JavaScript代码便可轻松实现,而无需借助其他一些JS插件库(如JQuery)或者前端开发开源工具包(如Bootstrap)。我们首先看下拉导航菜单的HTML代码:
<nav class="animenu"> <button class="animenu__toggle"> <span class="animenu__toggle__bar"></span> <span class="animenu__toggle__bar"></span> <span class="animenu__toggle__bar"></span> </button> <ul class="animenu__nav"> <li><a href="">HTML</a></li> <li><a href="">学习CSS3</a> <ul class="animenu__nav__child"> <li><a href="">CSS3 媒体查询</a></li> <li><a href="">CSS3 动画</a></li> <li><a href="">CSS3 新选择器</a></li> </ul> </li> <li><a href="">JavaScript</a> <ul class="animenu__nav__child"> <li><a href="">JavaScript 本地对象和内置对象</a></li> <li><a href="">Browser 对象(BOM)</a></li> <li><a href="">HTML DOM 对象</a></li> </ul> </li> <li><a href="">PHP</a></li> <li><a href="">MySQL</a></li> </ul> </nav>
符合HTML语义化的下拉导航菜单代码结构,再来看定义导航菜单的CSS样式规则:
<style type=="text/css="> /* 重置样式,用来覆盖不同浏览器渲染HTML元素时的各种默认样式。亦可以使用normalize.css */ html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;list-style:none;outline:none;-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} /* 设置HTML5的新元素为块级元素 */ article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block} table {border-collapse:collapse;border-spacing:0} img {border:0} .animenu__toggle {display:none;cursor:pointer;background-color:#111;border:0;padding:10px;height:40px;width:40px} .animenu__toggle:hover {background-color:#006699} .animenu__toggle__bar { display:block; width:20px; height:2px; background-color:white; -webkit-transition:0.15s cubic-bezier(0.75, -0.55, 0.25, 1.55); -o-transition:0.15s cubic-bezier(0.75, -0.55, 0.25, 1.55); transition:0.15s cubic-bezier(0.75, -0.55, 0.25, 1.55); } /* 使用相邻兄弟元素选择器+,设置第二和第三条白色小横线的上外边距为4像素 */ .animenu__toggle__bar + .animenu__toggle__bar{margin-top:4px} /* 当添加类名为animenu__toggle__active,将三条白色小横线变成一个×符号 */ .animenu__toggle__active .animenu__toggle__bar {margin:0;position:absolute} .animenu__toggle__active .animenu__toggle__bar:nth-child(1) { -webkit-transform:rotate(45deg); -ms-transform:rotate(45deg); -o-transform:rotate(45deg); transform:rotate(45deg); } .animenu__toggle--active .animenu__toggle__bar:nth-child(2) {opacity:0} .animenu__toggle--active .animenu__toggle__bar:nth-child(3) { -webkit-transform:rotate(-45deg); -ms-transform:rotate(-45deg); -o-transform:rotate(-45deg); transform:rotate(-45deg); } .animenu {display:block} .animenu ul {font-family:"Open Sans"} .animenu li, .animenu a {display:inline-block;font-size:15px} .animenu a {text-decoration:none;color:white} .animenu__nav {background-color:#111} .animenu__nav > li {position:relative;border-right:1px solid #444444} .animenu__nav > li > a {padding:10px 30px;text-transform:uppercase} .animenu__nav > li > a:first-child:nth-last-child(2):before { content:""; position:absolute; border:4px solid transparent; border-bottom:0; border-top-color:currentColor; top:50%; margin-top:-2px; right:10px; } .animenu__nav > li:hover > ul {opacity:1;visibility:visible;margin:0} .animenu__nav > li:hover > a {color:white} .animenu__nav__child { min-width:100%; position:absolute; z-index:1; left:0; top:100%; opacity:0; visibility:hidden; margin:20px 0 0 0; background-color:#373737; transition:margin .15s,opacity .15s; } .animenu__nav__child > li {width:100%;border-bottom:1px solid #515151} .animenu__nav__child > li:last-child {border:0} .animenu__nav__child > li:first-child > a:after { content:""; position:absolute; width:0; height:0; left:1em; top:-6px; border:6px solid transparent; border-top:0; border-bottom-color:inherit; } .animenu__nav__child a {width:100%;padding:10px;border-color:#373737} .animenu__nav__child a:hover {background-color:#006699;border-color:#006699;color:#fff} /* 媒体查询,当浏览器的视口宽度不大于768像素时应用以下样式 */ @media screen and (max-width:767px) { .animenu__toggle {display:inline-block} .animenu__nav, .animenu__nav__child {display:none} .animenu__nav {margin:10px 0} .animenu__nav > li {width:100%;border-right:0;border-bottom:1px solid #515151} .animenu__nav > li:last-child {border:0} .animenu__nav > li:first-child > a:after { content:""; position:absolute; height:0; width:0; left:1em; top:-6px; border:6px solid transparent; border-top:0; border-bottom-color:inherit; } .animenu__nav > li > a {position:relative;width:100%;padding:10px;border-color:#111} .animenu__nav a:hover {background-color:#006699;border-color:#006699;color:#fff} .animenu__nav__child {position:static;background-color:#373737;margin:0;transition:none;visibility:visible;opacity:1} .animenu__nav__child > li:first-child > a:after {content:none} .animenu__nav__child a {width:100%;padding-left:20px} } .animenu__nav__open {display:block !important} .animenu__nav__open .animenu__nav__child {display:block} </style>
要看懂以上CSS样式规则并不难,关键是CSS3实现动画的属性、伪对象(或称为伪元素)以及伪类的使用规则。最后在页面底部添加一个自执行匿名函数,绑定HTML的button元素的单击事件:
<script type="text/javascript"> /* 点击按钮显示导航菜单JS代码,无需载入其他JS库,使用原生的JavaScript方法实现 */ (function(){ var animenuToggle = document.querySelector('.animenu__toggle'), animenuNav = document.querySelector('.animenu__nav'), hasClass = function(elem, className) {return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');}, toggleClass = function(elem, className) { var newClass = ' ' + elem.className.replace(/[\t\r\n]/g, ' ') + ' '; if( hasClass(elem, className ) ) { while( newClass.indexOf(' ' + className + ' ') >= 0 ) { newClass = newClass.replace(' ' + className + ' ', ' '); } elem.className = newClass.replace(/^\s+|\s+$/g, ''); }else{ elem.className += ' ' + className; } }, animenuToggleNav = function (){ toggleClass(animenuToggle, "animenu__toggle__active"); toggleClass(animenuNav, "animenu__nav__open"); } if (!animenuToggle.addEventListener) { animenuToggle.attachEvent("onclick", animenuToggleNav); }else{ animenuToggle.addEventListener('click', animenuToggleNav); } })(); </script>