移動端友好的響應式導航欄教程
源自codrops團隊優良的設計理念,搬運且翻譯成中文。 原文地址:http://tympanus.net/codrops/2013/05/08/responsive-retina-ready-menu/
以下是譯文:
今天我來教大家設計一個色彩絢麗且移動端友好的響應式導航欄。這個導航欄的靈感源自一款叫做“無主之地(Borderlands)”游戲中的一個叫做Maliwan武器生產商商標所采用的顏色集。導航欄會自動根據瀏覽器窗口的大小調整布局格式:在PC寬度下呈現為一行按鈕,在平板寬度下呈現為三行按鈕,而在移動端則變成了一個菜單欄按鈕連接,點擊可以顯示和隱藏整個導航欄。為了使這個導航欄做到真正地移動端友好,我們將采用圖標字體來作為導航欄圖表,這樣的話,當界面放大縮小的時候,圖標也會自動調整分辨率,避免鋸齒(像素過高)和模糊(像素過低)。
準備工作:選擇圖標字體
圖標字體的制作不是一項簡單的任務,不過我們完全沒有必要給自己找這個麻煩。像IcoMoon,或者FontAwesome這樣的插件已經為我們準備好了現成的圖標以供選擇,我們也可以使用這些工具快速創造自己需要的圖標字體。使用圖標文字的好處是這些圖標像Web字體一樣,我們可以輕松地改變它的顏色和大小,而不會出現類似圖片放大之后模糊的情形。因此我們就省得為移動端再準備不同分辨率大小的同個圖片了。
首先我們需要制作自己所需要的圖標按鈕(當然你也可以選擇插件已經制作好的圖標文字)。我主要使用Adobe Illustrator來制作矢量圖,當然其他類似的矢量圖制作工具也可以完成這個任務。我們首先需要在矢量圖制作工具中做好所需的按鈕,然后將它們導出為SVG格式的文件。為了確保在所有瀏覽器中顯示正常,我們必須把設計元素時的不同線條組合成一個完整的對象,然后將每一個圖標導入到IcoMoon App Tool中:
導入好這些元素之后,點擊右下角下載旁邊的設置按鈕,我們可以對生成的字體進行詳細的配置,包括字體編碼格式,給每個字體分配對應的字符等。當然大多數情況下默認的配置是能夠滿足需要的,這時候我們只要直接點擊下載按鈕,就可以獲得整個字體包和相關文件了。
獲得圖標字體之后,第一件事當然是放到我們的項目中查看效果。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); }
我們先給按鈕添加一個鼠標懸停效果,當鼠標懸停在按鈕上方時,這個按鈕的變得半透明。
/* 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導航欄的制作,怎么樣,是不是很簡單啊?
來自:http://my.oschina.net/jndion/blog/418964