今天我来教你们设计一个色彩绚丽且移动端友好的响应式导航栏。这个导航栏的灵感源自一款叫作“无主之地(Borderlands)”游戏中的一个叫作Maliwan武器生产商商标所采用的颜色集。导航栏会自动根据浏览器窗口的大小调整布局格式:在PC宽度下呈现为一行按钮,在平板宽度下呈现为三行按钮,而在移动端则变成了一个菜单栏按钮链接,点击能够显示和隐藏整个导航栏。为了使这个导航栏作到真正地移动端友好,咱们将采用图标字体来做为导航栏图表,这样的话,当界面放大缩小的时候,图标也会自动调整分辨率,避免锯齿(像素太高)和模糊(像素太低)。javascript
###准备工做:选择图标字体html
图标字体的制做不是一项简单的任务,不过咱们彻底没有必要给本身找这个麻烦。像IcoMoon,或者FontAwesome这样的插件已经为咱们准备好了现成的图标以供选择,咱们也可使用这些工具快速创造本身须要的图标字体。使用图标文字的好处是这些图标像Web字体同样,咱们能够轻松地改变它的颜色和大小,而不会出现相似图片放大以后模糊的情形。所以咱们就免得为移动端再准备不一样分辨率大小的同个图片了。java
首先咱们须要制做本身所须要的图标按钮(固然你也能够选择插件已经制做好的图标文字)。我主要使用Adobe Illustrator来制做矢量图,固然其余相似的矢量图制做工具也能够完成这个任务。咱们首先须要在矢量图制做工具中作好所需的按钮,而后将它们导出为SVG格式的文件。为了确保在全部浏览器中显示正常,咱们必须把设计元素时的不一样线条组合成一个完整的对象,而后将每个图标导入到IcoMoon App Tool中:web
导入好这些元素以后,点击右下角下载旁边的设置按钮,咱们能够对生成的字体进行详细的配置,包括字体编码格式,给每一个字体分配对应的字符等。固然大多数状况下默认的配置是可以知足须要的,这时候咱们只要直接点击下载按钮,就能够得到整个字体包和相关文件了。浏览器
得到图标字体以后,第一件事固然是放到咱们的项目中查看效果。IcoMoon下载包中提供了必要的4类字体文件资源,对应不一样的浏览器,同时还有响应的CSS样式。更方便的是它还提供了一个demo.html文件,咱们能够直接在其中看到自定义图标的效果。工具
###按钮的HTML实现布局
<nav id="menu" class="nav"> <ul> <li> <a href="#" title=""> <span class="icon"> <i aria-hidden="true" class="icon-home"></i></span><span>Home</span> </a> </li> <li> <a href="#" title=""><span class="icon"> <i aria-hidden="true" class="icon-services"></i></span><span>Services</span></a> </li> <li> <a href="#" title=""><span class="icon"><i aria-hidden="true" class="icon-portfolio"></i></span><span>Portfolio</span></a> </li> <li> <a href="#" title=""><span class="icon"><i aria-hidden="true" class="icon-blog"></i></span><span>Blog</span></a> </li> <li> <a href="#" title=""><span class="icon"><i aria-hidden="true" class="icon-team"></i></span><span>The team</span></a> </li> <li> <a href="#" title=""><span class="icon"><i aria-hidden="true" class="icon-contact"></i></span><span>Contact</span></a> </li> </ul> </nav>
在网页中使用图标字体的方法很是简单,只须要在一个i标签或者span标签元素中增长名叫“icon-iconname”的class属性就能够了。这里要提一下,咱们通常会在body标签中添加no-js这个class属性,当使用modernizr时,若是浏览器没有禁用javascript,那么modernizr会自动把no-js改为js。这样作的好处是,假如浏览器禁用了脚本,咱们能够经过这个class属性让导航栏默认处于展开的状态。Modernizr的功能十分强大,咱们还能够用它来检测移动设备对触屏的支持如何,并作出应对策略。字体
###CSS和Javascript的实现动画
/* 全局CSS配置,将在全部设备下生效 */ .nav ul { max-width: 1240px; margin: 0; padding: 0; list-style: none; font-size: 1.5em; font-weight: 300; } .nav li span { display: block; } .nav a { display: block; color: rgba(249, 249, 249, .9); text-decoration: none; transition: color .5s, background .5s, height .5s; } .nav i{ /* 确保图标文字在谷歌浏览器下显示清晰 */ transform: translate3d(0, 0, 0); } /* 去掉webkit内核下点击按钮出现的蓝色背景 */ a, button { -webkit-tap-highlight-color: rgba(0,0,0,0); }
咱们先给按钮添加一个鼠标悬停效果,当鼠标悬停在按钮上方时,这个按钮的变得半透明。this
/* PC端鼠标悬停在按钮上方时的特效 */ .no-touch .nav ul:hover a { color: rgba(249, 249, 249, .5); } .no-touch .nav ul:hover a:hover { color: rgba(249, 249, 249, 0.99); }
下面咱们介绍一个方法,能够在不用给每一个li元素添加不一样class属性的状况下,分别给他们赋予不一样的显示效果,这就是li:nth-child。咱们经过这种方法给列表中的每个按钮赋予不一样的颜色。
.nav li:nth-child(6n+1) { background: rgb(208, 101, 3); } .nav li:nth-child(6n+2) { background: rgb(233, 147, 26); } .nav li:nth-child(6n+3) { background: rgb(22, 145, 190); } .nav li:nth-child(6n+4) { background: rgb(22, 107, 162); } .nav li:nth-child(6n+5) { background: rgb(27, 54, 71); } .nav li:nth-child(6n+6) { background: rgb(21, 40, 54); }
接下来介绍一下响应式界面设计基础中的基础,那就是@media的应用。这里顺带简单介绍一下em这个单位,em指的是相对于body全局字体大小,若是body全局字体大小是15px,那么50em就等于800px。这样作的好处是当body字体调整时,整个页面的大小均可以跟着动态变化,有利于移动端的适配。
@media (min-width: 50em) { /* 当屏幕的宽度小于50em时,将水平的导航栏转换成垂直的列表格式 */ .nav li { float: left; width: 16.66666666666667%; text-align: center; transition: border .5s; } .nav a { display: block; width: auto; }
咱们给每一个按钮添加选中点击时彩色的底边。加上focus和active这两个选项,这样当移动设备选中和使用键盘选中的时候也能够看到效果。
/* 悬浮、选中和点击的状况下出现彩色的底边 */ .no-touch .nav li:nth-child(6n+1) a:hover, .no-touch .nav li:nth-child(6n+1) a:active, .no-touch .nav li:nth-child(6n+1) a:focus { border-bottom: 4px solid rgb(174, 78, 1); } .no-touch .nav li:nth-child(6n+2) a:hover, .no-touch .nav li:nth-child(6n+2) a:active, .no-touch .nav li:nth-child(6n+2) a:focus { border-bottom: 4px solid rgb(191, 117, 20); } .no-touch .nav li:nth-child(6n+3) a:hover, .no-touch .nav li:nth-child(6n+3) a:active, .no-touch .nav li:nth-child(6n+3) a:focus { border-bottom: 4px solid rgb(12, 110, 149); } .no-touch .nav li:nth-child(6n+4) a:hover, .no-touch .nav li:nth-child(6n+4) a:active, .no-touch .nav li:nth-child(6n+4) a:focus { border-bottom: 4px solid rgb(10, 75, 117); } .no-touch .nav li:nth-child(6n+5) a:hover, .no-touch .nav li:nth-child(6n+5) a:active, .no-touch .nav li:nth-child(6n+5) a:focus { border-bottom: 4px solid rgb(16, 34, 44); } .no-touch .nav li:nth-child(6n+6) a:hover, .no-touch .nav li:nth-child(6n+6) a:active, .no-touch .nav li:nth-child(6n+6) a:focus { border-bottom: 4px solid rgb(9, 18, 25); }
调整图标的相对位置和渐变效果:
/* 调整图标的位置 */ .icon { padding-top: 1.4em; } .icon + span { margin-top: 2.1em; transition: margin .5s; }
当鼠标悬停在按钮上方时,改变元素的高度,产生动画效果:
/* 鼠标悬停的时候出现高度变化动画 */ .nav a { height: 9em; } .no-touch .nav a:hover , .no-touch .nav a:active , .no-touch .nav a:focus { height: 10em; } /* 这里让文字跟着整个元素的高度变化而变化 */ .no-touch .nav a:hover .icon + span { margin-top: 3.2em; transition: margin .5s; }
调整按钮的位置,并设计CSS渐变效果:
/* 调整按钮的位置,并设计CSS渐变效果 */ .nav i { position: relative; display: inline-block; margin: 0 auto; padding: 0.4em; border-radius: 50%; font-size: 1.8em; box-shadow: 0 0 0 0.8em transparent; background: rgba(255,255,255,0.1); transform: translate3d(0, 0, 0); transition: box-shadow .6s ease-in-out; }
为了得到咱们想要的效果,咱们改变盒模型的阴影,并将它的大小从0.8em渐变到0,将它的颜色从透明转变到一个相对不透明的状态。
/* 盒模型阴影动画效果 */ .no-touch .nav a:hover i, .no-touch .nav a:active i, .no-touch .nav a:focus i { box-shadow: 0 0 0px 0px rgba(255,255,255,0.2); transition: box-shadow .4s ease-in-out; } }
稍微调整一下屏幕宽度在800-980px之间时的位置:
@media (min-width: 50em) and (max-width: 61.250em) { /* Size and font adjustments to make it fit better */ .nav ul { font-size: 1.2em; } }
这样算是完成了PC端的设计了,固然如今不少平板甚至手机的分辨率都已经达到1024px以上了,PC和移动端的界限愈来愈模糊。
/* 设计800px如下的屏幕布局样式和特效 */ @media (max-width: 49.938em) { /* 多排按钮不能用改变border的特效,咱们换成改变背景透明度的特效 */ .no-touch .nav ul li:nth-child(6n+1) a:hover, .no-touch .nav ul li:nth-child(6n+1) a:active, .no-touch .nav ul li:nth-child(6n+1) a:focus { background: rgb(227, 119, 20); } .no-touch .nav li:nth-child(6n+2) a:hover, .no-touch .nav li:nth-child(6n+2) a:active, .no-touch .nav li:nth-child(6n+2) a:focus { background: rgb(245, 160, 41); } .no-touch .nav li:nth-child(6n+3) a:hover, .no-touch .nav li:nth-child(6n+3) a:active, .no-touch .nav li:nth-child(6n+3) a:focus { background: rgb(44, 168, 219); } .no-touch .nav li:nth-child(6n+4) a:hover, .no-touch .nav li:nth-child(6n+4) a:active, .no-touch .nav li:nth-child(6n+4) a:focus { background: rgb(31, 120, 176); } .no-touch .nav li:nth-child(6n+5) a:hover, .no-touch .nav li:nth-child(6n+5) a:active, .no-touch .nav li:nth-child(6n+5) a:focus { background: rgb(39, 70, 90); } .no-touch .nav li:nth-child(6n+6) a:hover, .no-touch .nav li:nth-child(6n+6) a:active, .no-touch .nav li:nth-child(6n+6) a:focus { background: rgb(32, 54, 68); } .nav ul li { transition: background 0.5s; } }
屏幕大小在520px到799px之间时,让导航栏按照2X3的形式进行布局。
/* 导航栏按照2X3的形式布局 */ @media (min-width: 32.5em) and (max-width: 49.938em) { /* 用左浮动的方法实现两个按钮并排 */ .nav li { display: block; float: left; width: 50%; } /* 加入padding使得元素按钮看上去好看些 */ .nav a { padding: 0.8em; } /* 用inline-block可让按钮在左边,文字在右边 */ .nav li span, .nav li span.icon { display: inline-block; } .nav li span.icon { width: 50%; } .nav li .icon + span { font-size: 1em; } .icon + span { position: relative; top: -0.2em; }
PC端的元素大小变化没法在平板布局下实现,所以咱们简化动画效果。
/* 在平板布局的情形下,咱们以一种更为保守的方式设计动画,只改变一下border的大小 */ .nav li i { display: inline-block; padding: 8% 9%; border: 4px solid transparent; border-radius: 50%; font-size: 1.5em; background: rgba(255,255,255,0.1); transition: border .5s; } /* border颜色渐变效果 */ .no-touch .nav li:hover i, .no-touch .nav li:active i, .no-touch .nav li:focus i { border: 4px solid rgba(255,255,255,0.1); } }
平板布局下,调整文字的大小和宽度
/* 平板布局下,调整文字的大小和宽度 */ @media (min-width: 32.5em) and (max-width: 38.688em) { .nav li span.icon { width: 50%; } .nav li .icon + span { font-size: 0.9em; } }
对于更小的移动设备,咱们能够隐藏整个导航栏,而后显示一个导航按钮,这样经过点击导航按钮来显示和隐藏导航栏。这个功能可能须要经过Javascript来实现。(译者:更简单的途径是使用jQuery的toggleClass方法实现)。
// 切换class属性的方法 var changeClass = function (r,className1,className2) { var regex = new RegExp("(?:^|\\s+)" + className1 + "(?:\\s+|$)"); if( regex.test(r.className) ) { r.className = r.className.replace(regex,' '+className2+' '); } else{ r.className = r.className.replace(new RegExp("(?:^|\\s+)" + className2 + "(?:\\s+|$)"),' '+className1+' '); } return r.className; }; // 写入菜单栏按钮 var menuElements = document.getElementById('menu'); menuElements.insertAdjacentHTML('afterBegin','<button type="button" id="menutoggle" class="navtoogle" aria-hidden="true"><i aria-hidden="true" class="icon-menu"> </i> Menu</button>'); // 点击菜单栏按钮时切换class属性 document.getElementById('menutoggle').onclick = function() { changeClass(this, 'navtoogle active', 'navtoogle'); } // 点击文档其余位置时自动隐藏导航栏 document.onclick = function(e) { var mobileButton = document.getElementById('menutoggle'), buttonStyle = mobileButton.currentStyle ? mobileButton.currentStyle.display : getComputedStyle(mobileButton, null).display; if(buttonStyle === 'block' && e.target !== mobileButton && new RegExp(' ' + 'active' + ' ').test(' ' + mobileButton.className + ' ')) { changeClass(mobileButton, 'navtoogle active', 'navtoogle'); } }
这一段采用Javascript原生的方法来进行class属性的切换和点击动做进行DOM文档操做的实现。当按钮点击的时候,首先判断按钮带有什么属性,而后改为另外一个属性,这样就实现了class属性的切换。实现了导航栏的隐藏与显示以后,咱们接着设置一下样式。
/* 导航栏按钮的样式,默认隐藏 */ .nav .navtoogle{ display: none; width: 100%; padding: 0.5em 0.5em 0.8em; font-family: 'Lato',Calibri,Arial,sans-serif; font-weight: normal; text-align: left; color: rgb(7, 16, 15); font-size: 1.2em; background: none; border: none; border-bottom: 4px solid rgb(221, 221, 221); cursor: pointer; } .navtoogle i{ z-index:-1; } .icon-menu { position: relative; top: 3px; line-height: 0; font-size: 1.6em; }
若是检测到屏幕小于519px,则显示这个导航栏按钮
@media (max-width: 32.438em) { /* 显示导航栏按钮 */ .nav .navtoogle{ margin: 0; display: block; }
接下来咱们实现导航栏的显示和隐藏动画。咱们经过元素的高度控制显示和隐藏。特别要提出,若是检测到页面禁用了脚本,咱们应该让导航栏默认是显示的。
/* 若是禁用了脚本,那么导航栏老是显示的。 */ .no-js .nav ul { max-height: 30em; overflow: hidden; } /* 若是脚本是可生效的,那么咱们控制高度为0,隐藏之 */ .js .nav ul { max-height: 0em; overflow: hidden; } /* class的active属性激活以后,给max-height一个动画效果,就可以实现导航栏向下滚动出现的特效 */ .js .nav .active + ul { max-height: 30em; overflow: hidden; transition: max-height .4s; }
而后给这个小屏导航栏设置样式
/* 小屏幕导航栏样式设置 */ .nav li span { display: inline-block; height: 100%; } .nav a { padding: 0.5em; } .icon + span { margin-left: 1em; font-size: 0.8em; }
左侧增长一个border效果(设计师须要多多关注这些细节:))
/* 左侧增长一个border效果 */ .nav li:nth-child(6n+1) { border-left: 8px solid rgb(174, 78, 1); } .nav li:nth-child(6n+2) { border-left: 8px solid rgb(191, 117, 20); } .nav li:nth-child(6n+3) { border-left: 8px solid rgb(13, 111, 150); } .nav li:nth-child(6n+4) { border-left: 8px solid rgb(10, 75, 117); } .nav li:nth-child(6n+5) { border-left: 8px solid rgb(16, 34, 44); } .nav li:nth-child(6n+6) { border-left: 8px solid rgb(9, 18, 25); }
接下来不少工做可能都是在调整移动端设备的效果上面了。咱们使用Modernizr这个工具能够很方便的帮咱们识别移动设备的兼容性,这样咱们能够经过class属性来为特性支持或者特性不支持的设备进行调整。好比这个导航栏的按钮在PC下面显示正常,可是一样的样式在手机设备上可能显得过小,很差按。这时候咱们这样能够进行样式的调整。
/* 让导航栏在触屏设备下看起来更温馨一些 */ .touch .nav a { padding: 0.8em; } }
这样咱们就完成了一个至关绚丽的CSS3导航栏的制做,怎么样,是否是很简单啊?