九個適應性設計小撇步,把你的網站打造成變形金剛!(下篇)

接續上一篇所介紹的一些基本 CSS 排版小技巧,本文第一部分開始介紹 CSS media queries 常見的使用方式,以及一些在開發初期就要先注意的地方;第二部分則介紹一些適應性設計相關的工具及 Javascript 套件。希望這些小撇步可以幫助你在開發網站上事半功倍囉!

運用 CSS media queries

撇步四:排版避免設定高度及絕對位置,寬度設定儘量集中

右下角可拖曳縮放↗

從這個範例中可以看到有三個不同顏色 

div
分別包了三個白底的文字區塊,假設有個前端需求是三個文字區塊要隨著螢幕寬度動態改變寬度,這時最好的作法是將三個區塊指定同樣的
class
,這樣一來在設定 media queries 時就只需要覆寫一個 
class
的設定:
.container {
    width: 500px;
}

@media only screen and (max-width: 540px) {
    .container {
        width: 400px;
    }
}

@media only screen and (max-width: 440px) {
    .container {
        width: 300px;
    }
}

這樣一來當螢幕寬度小於 

540px
  時,三個文字區塊的寬度就會縮成
400px
,以此類推。若三個文字區塊各自用三個不同的 CSS 選擇器來指定寬度,那麼 media queries 也必須使用同樣的三個 CSS 選擇器來覆寫原本的 CSS,當寬度設定要改變時,要修改的地方就變得更多。另外也可以看到這個範例中沒有設定任何的高度以及絕對定位,這也是為了維護方便的考量。

為了讓大家能夠實際瞭解沒有注意這些規則的後果,這次破例來個錯誤示範:

右下角可拖曳縮放↗

在這個錯誤示範中我刻意使用了三組不同的 CSS 選擇器來設定三個文字區塊,並且還很假掰的設定高度和絕對定位來進行排版。當然正常人對於這種排版應該是不會這樣實做的,我只是要提醒大家儘量少用這樣的排版方式,否則將來會很難維護。

雖然表面上看起來有達到一模一樣的效果,但可以看到這邊 CSS 的行數從原本的 32 行爆增到 93 行,足足多了兩倍!且來回修改 px 值對位置不僅曠日費時,如果到時候需求改變突然要增加一個區塊在最上方時,這樣的 code 要改下去只能用欲哭無淚來形容,慎之!

撇步五:隱藏暫不需要的選單、展開隱藏的頁籤

在 RWD 網站中常用技巧之一就是把選項太多的選單暫時藏起來,等到點擊或是游標經過再顯示出來:

右下角可拖曳縮放↗

大家試著拖曳這個 jsfiddle 範例的右下角,可以發現寬度拉到小於 

400px
時,原本左邊的綠色選單就不見了,縮成一個綠色選單鈕,滑鼠放上去時選單就會自動展開,要做到這個選單效果其實只需要加上底下的 media queries 設定:
@media only screen and (max-width: 400px) {
    nav {
        position: fixed;
    }
    nav > ul {
        display: none;
    }
    #menu-toggle {
        display: block;
    }
    nav:hover > ul {
        display: block;
        margin-top: 30px;
    }
}

把 

nav
設定為 
position: fixed
是為了讓選單鈕常駐在上方,
nav > ul
設定為 
display: none
把選單內容隱藏起來,而原本有一個隱藏的選單鈕元素 
#menu-toggle
則在此時設定為
display: block
,這樣就只剩下一個選單鈕浮在上方了。如何讓選單在游標經過時展開來呢?其實很簡單,只要運用 CSS 的 
:hover
選擇器,
nav:hover > ul
這個選擇器設定了當游標經過 nav 元素時,將 
nav
元素內的第一層 
ul
顯示出來。因為 
nav
元素沒有特別設定寬高或顯示模式,所以它的 
:hover
感應範圍將完全符合內含元素。也就是說,當選單收合時,
nav
的感應範圍也縮小到和 
#menu-toggle
一樣大小,而當選單展開時,
nav
的感應範圍就是 
#menu-toggle
以及 
nav > ul
所聯集起來的範圍,如此一來選單展開時,就算游標移到 
nav > ul
內也不必擔心選單會消失。若將 
:hover
選擇器掛在
#menu-toggle
上,游標只要一離開選單鈕,選單就會收合,使用者就永遠無法點擊選單的內容了。

另一個 RWD 常見的作法是把原本隱藏在不同頁籤的內容顯示出來。因為手機上畫面空間不足,通常不適合使用頁籤,這時不如把內容直接展開來,使用者只要向下滑動即可輕鬆 瀏覽內容。大家試試拖曳底下 jsfiddle 的右下角,寬度縮到 

400px
以下時三個頁籤的內容就會展開來。
右下角可拖曳縮放↗

在這個範例中使用了一個純 CSS 的頁籤,基本原理是透過 

label
連帶驅動 
radio
鈕,再使用 CSS 選擇器選擇 
checked
radio
鈕,並將它鄰近的頁籤內容顯示出來。這是其中一個頁籤的 HTML 定義:
  • Mozilla 基金會邀請支持此宣言理念的眾人,一同探索實踐這份網際網路願景的新方法

  • 頁籤鈕的部分是 

    label
    元素,可以看到它透過 
    for="tab3"
    的設定對應到一個隱形的 
    radio
    鈕,這樣一來只要頁籤被按下,此 
    radio
    的狀態就會顯示為
    checked
    ,而其它頁籤對應的 
    radio
    鈕 
    checked
    狀態則會消失。使用 
    radio
    鈕正是因為它的特性和頁籤很像,同一時間只能選取其一,且只要透過 CSS 選擇器 
    :checked
    即可偵測其狀態進而改變頁籤以及內容的樣式:
    .tabs [name="tabs"]:checked + label { 
        top: 0;
        padding-top: 17px; 
        background: #FFF; 
    }
    .tabs [name="tabs"]:checked ~ .tab-content {
        display: block;
    }

    這段 CSS 就是奇蹟發生的所在,可以看到這邊用了兩次

    .tabs [name="tabs"]:checked
    選擇器,第一次搭配 
    +
    選擇器,選擇鄰近的下一個 sibling label 元素(也就是頁籤),把頁籤設定成白色並往上浮起。第二次則是搭配 
    ~
    選擇器選擇較遠的頁籤內容元素
    .tab-content
    ,將其設為 
    display: block
    以顯示其內容。這樣一來我們就有一組純 CSS 的頁籤了。這裡用到兩個大家可能較少見的 CSS sibling 選擇器,有興趣可以看一下 MDN 上的這兩頁文件:Adjacent sibling selectorsGeneral sibling selectors

    那麼又要如何讓它在螢幕變小時展開呢?其實也不是太難:

    @media only screen and (max-width: 400px) {
      .tabs {
        width: 100%;
      }
      .tabs li {
        float: none;
        margin-top: 20px;
      }
      .tabs .tab-content {
        position: relative;
        display: block;
        top: 0;
      }
      .tabs label {
        top: 0;
        padding-top: 17px; 
        background: #FFF;       
      }
      .tabs label:hover {
        background: #FFF;
      }
    }

    首先把 

    .tabs
    寬度設為百分比,讓內容隨螢幕寬度自動調整。然後取消 
    .tabs li
    的浮動狀態,設定
    float: none
    ,讓 
    .tabs li
    依序往下排列,接著把所有的 
    .tab-content
    設為
    display: block
    強制顯示出來,最後再把 
    label
    調整為統一的樣式即可。

    這個撇步介紹了兩個透過 media queries 在小螢幕裝置上顯示/隱藏內容的範例,這些內容隱藏起來並不是再也不會被用到,而是要等游標經過或者點擊等事件才會顯現。但如果你發現網頁裡有太多元素內容在不同的 media queries 設定裡被藏起來完全沒機會使用到,那麼就要好好思考這些元素存在的必要性。當然也可以使用 Javascript 動態載入內容、或是在後端偵測

    User Agent
    標頭偵測再決定要不要送出這些元素到前端來。

    撇步六:使用相對字級設定

    右下角可拖曳縮放↗

    如果網頁內某些文字區塊的字體是有相對大小關係的,那麼建議可以使用相對字級設定。以這個範例來看,假設三行字前後兩行是相對於中間那行較大/較小的字體,那麼其實我們只需要明確設定中間那行字的字體大小,前後兩行字分別套用

    large
    /
    small
    兩個
    class
    ,可以看到上面 jsfiddle 中兩個 
    class
    的定義 :
    .large {
        font-size: larger;
    }
    .small {
        font-size: smaller;
    }

    這裡使用的是

    larger
    /
    smaller
    兩組相對值,你也可以使用 
    em
    或者百分比等單位來指定相對的大小比例,詳細的相對字級設定請參閱 MDN 說明文件

    有了相對字級設定,在加上 media queries 時也會輕鬆一些:

    @media only screen and (max-width: 500px) {
        #container {
            font-size: 15px;
        }
    }
    @media only screen and (max-width: 300px) {
        #container {
            font-size: 10px;
        }
    }

    只需要更改中間文字的基準字體大小,前後兩行字就會自動根據基準字體套用比例進行縮放,大家可以拖曳這個範例 jsfiddle 的右下角試試看。

    善用各種工具及套件

    撇步七:使用 Firefox 特有開發工具-適應性設計檢視

    你現在用的是最新版本的 Firefox 嗎?從 2012 年的 Firefox 15.0 開始誕生了一個方便的新工具-適應性設計檢視 (Responsive Design View),如果你現在用的就是 Firefox,馬上試試按下快速鍵 Ctrl+Shift+M (Windows 及 Linux 平台) 或者 Cmd+Opt+M (Mac 平台),或是從網頁開發者選單裡啟用,要關閉只要再按一次快速鍵或是從選單裡再選擇一次即可。請看以下短片介紹:

    當然你如果有 Android 手機,可以安裝 Firefox for Android 並參考此 MDN 線上文件直接從桌面版 Firefox 連接手機測試及除錯你的行動網頁。其它像 Android 的 Chrome 瀏覽器以及 iOS 的 Safari 瀏覽器也支援透過電腦連接手機進行網頁除錯。

    撇步八:Javascript 界的 media queries-enquire.js 及 Modernizr

    前面提到過 RWD 不等於 media queries,如果你以為 Javascript 只有乾坐在一旁看戲的份那可就錯了。善用 Javascript 搭配 CSS,開發 RWD 網站可說是如虎添翼呀。

    首先介紹 enquire.js,它的特色就是寫法和 media queries 非常類似:

    enquire.register("screen and (max-width: 760px)", {
        match : function() {
            // Match tablet
        },
        unmatch : function() {
            // Larger than tablet
        }
    }).register("screen and (max-width: 480px)", {
        match : function() {
            // Match mobile landscape
        },
        unmatch : function() {
            // Larger than mobile landscape
        }
    });

    可以看到 

    enquire.register()
    方法的第一個參數 “screen and (max-width: 760px)”,其意義就和 CSS media queries 的設定是一樣的。

    Modernizr 的用途則是偵測目前瀏覽器是否支援特定功能(如 Canvas、HTML5 Video/Audio 等等),在 Javascript 中只要使用 Modernizr 物件就可以針對各種瀏覽器的先進功能進行偵測,如 

    Modernizr.canvas
    回傳 
    true
    表示瀏覽器支援 Canvas 功能,這時就可以在 Javascript 裡作判斷並加上對應的功能。

    除了可以在 Javascript 中偵測瀏覽器支援外,Modernizr 還可針對你要偵測的功能在 

    html
    標籤上加上相對應的
    class
    ,如
     表示目前的瀏覽器支援 CSS 動畫,這樣一來只要在 CSS 裡針對 Modernizr 加的 
    class
    進行設定(例如在 CSS 動畫定義選擇器前面都加上
    .cssanimations
    ),即可偵測不同瀏覽器的支援度而呈現出不同的結果。

    Modernizr 的另一個功能是可以讓你在偵測到某些功能不支援時(這邊不限於 Modernizr 本身支援偵測的功能),動態載入向下相容的 polyfills 套件。拿 enquire.js 來舉例,搭配 Modernizr 可以偵測瀏覽器是否支援 enquire.js 套件所使用到的

    window.matchMedia
    功能,如果未支援則載入 media-match polyfills 向下相容套件
    Modernizr.load([
        //first test need for polyfill
        {
            test: window.matchMedia,
            nope: "/path/to/polyfill.js"
        },
    
        //and then load enquire
        "/path/to/enquire.js",
        "/path/to/your/script.js"
    ]);

    善用這些工具搭配不同的 CSS 和 Javascript 套件,可以有效增加你的網頁支援度。

    撇步九:使用支援適應性設計的 Javascript 套件

    在研究比較適用的 Javascript 套件時,可以先把適應性設計的支援考慮進去,這裡介紹兩個實用的套件: Owl Carousel 輪播看板、以及前陣子很流行的 Masonry 排版引擎等等。

    右下角可拖曳縮放↗

    OwlCarousel 除了可以流暢支援觸控事件以外,還提供了一些進階設定,讓開發者可以指定特定螢幕大小下同時出現的看板數目:

    $("#owl-example").owlCarousel({
        itemsCustom: [[600,5],[500,4],[400,3],[300,2],[200,1]]
    });

    這個範例裡透過 itemsCustom 設定傳入一個二維陣例,分別指定不同螢幕大小的看板數目,例如

    [500,4]
    表示螢幕寬度小於 500px 時只顯示四個看板。這邊設定成螢幕寬度每少 100px,看板就少顯示一個。大家可以拖曳上面 jsfiddle 的右下角看看效果。

    實際的應用可以參考 MyFirefox 行動版首頁以及狐電視行動版(要用手機開啟才看得到)。

    右下角可拖曳縮放↗

    Masonry 神奇的地方就是它幾乎不需要多餘的設定,就可以使不規則排列的區塊自動向上填補空白,而且畫面變小時還會自動往下跑,大家可以試著拖曳右下角調整 jsfiddle 大小看看。

    有時候會發現填補後仍出現小塊空白或參差不齊,想減少這種狀況發生,有三個秘訣:

    1. 所有區塊的長寬必須有倍數關係,例如最小區塊長度單位是 60px,那麼所有區塊的長度都要是 60px 的倍數。
    2. 最小的區塊數目要最多,以利填補空位。
    3. 嘗試交換區塊前後順序以達到最佳效果(第一個區塊寬度必須是最小的,因為 Masonry 會拿它作為基本單位)

    Masonry 排版引擎同樣也應用在我們的 MyFirefox 桌面版首頁以及謀智台客編輯牆

    總結

    看完這兩篇文章以後,是不是對適應性設計有更深入的了解呢?這些小撇步是不是也可以拿來應用在自己的網站上?

    網頁設計的世界博大精深,同樣的問題可能有很多種解決方式,這一系列兩篇文章提到的小技巧並不是全部,也不一定適用於所有人。保持開放的態度,並勇於嘗試,總會找到最適合自己的方式。也歡迎大家留言分享自己的小撇步喔~