移動端友好的響應式導航欄教程

jopen 9年前發布 | 59K 次閱讀 響應式 移動開發

源自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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!