今天我來教你們設計一個色彩絢麗且移動端友好的響應式導航欄。這個導航欄的靈感源自一款叫作「無主之地(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導航欄的製做,怎麼樣,是否是很簡單啊?