響應式 Web 設計技巧

developerworks發表於2015-06-17

  本文結合例項,詳述建立一個響應式網站的實用技巧。重點側重於探討響應式網站技術 Media Query, 並提供相應 HTML、CSS、JS程式碼,幫助您快速打造響應式網站。針對響應式圖片、響應式表格、響應式視訊方案也將逐一介紹,探討針對各種螢幕大小設計和開發響應式網站的解決方案。

 什麼是響應式設計?

  iOS 和 Android 的釋出,智慧手機、平板電腦、智慧家電等新裝置層出不窮,極大便利了我們的生活,但面對形形色色的終端裝置,千差萬別的螢幕解析度,給網頁設計帶來了新的挑戰,我們無法估計使用者的終端裝置和網路狀況,更不可能為每種裝置都專門設計一套網站,如何實現 Web UI 在多終端中的適配呢?2010 年 Ethan Marcotte 曾經在 A List Apart 發表過一篇文章"Responsive Web Design",響應式網頁設計提供了一種設計方法,可以使同一網站在智慧手機、桌面電腦,以及介於這兩者之間的任意裝置上完美顯示。這種方法能夠根據使用者的螢幕尺寸,合理地為現有及將來的各種裝置提最佳的瀏覽體驗。

  http://mediaqueri.es/ 這是一個響應式設計創意收集網站,可以在上面檢視到很多響應式設計例項,較多的網站都應用了 Mobile First 設計思想,先針對小視口裝置進行設計,然後逐步對大視口設計進行漸進增強支援。

  圖 1. Froont 響應式設計網站截圖

Froont 響應式設計網站截圖

  這也意味著設計思維的轉換,不應再執著於佈局、線框等的具體大小,而應該考慮如何使用流體元素。與其根據不同裝置的大小來設計頁面,更著重考慮如何針對內容進行設計。拋棄畫素,拋棄固定寬度,先從小螢幕進行設計,然後逐步增強針對大螢幕的設計

  當然也需要引導客戶,網站不必在所有瀏覽器中表現一致,時間應該花在更有價值的地方,而不是花大量時間修復爛瀏覽器固有的缺陷。核心思想就是,優雅降級,內容優先。

 響應式設計是最佳選擇嗎?

  實際專案中,什麼時候我們需要用到響應式設計呢?並非所有的頁面呈現,內容設計問題都可以通過響應式設計思路解決,專案的預算、目標使用者及定位決定了其實現方式。

  舉幾個例子來說,如果一個提供促銷內容的網站,我們可以通過 CSS3 媒體查詢技術,根據視口大小為使用者提供與之匹配的視覺效果,迎合小螢幕的同時相容超大螢幕,不同的視覺展示方式來響應各種設計大小,提供更好的使用者體驗和無歧視的設計,比如為小螢幕提供更容易手指操作的設計同時,為超大螢幕提供內容也能提供額外改進,這時響應式設計是優選。如果是一個預算充足的點餐網站,定製一個真正的“手機移動版”更為合適,使用者可基於 GPS 找到附近的店家點餐,或者是一個 dashboard 網站,有大量的資料內容和管理命令,此時單獨的響應式設計方案遠遠不能支撐這種解決方案。任何工具或技術都應該只在應用程式需要它的時候使用,IE 7 和 8 不支援 HTML5、CSS3 的新屬性。如果一個網站的絕大多數使用者都使用 IE 7 或 8,或更低版本,做成響應式意義也不大,但不代表做不到。

  總結下來,響應式設計的優點是靈活性強,適應不同解析度的裝置,缺點是相容各種裝置導致程式碼臃腫,載入時間加長。

  選擇在現有程式碼基礎上的增強的折中性響應式設計?還是選擇一個真正的“手機版”,要依賴於專案實際情況。

 什麼是視口(viewport)和螢幕尺寸(screen.width)?

  視口和螢幕尺寸不是同一個概念。視口(viewport),即可視區域的大小,是指瀏覽器視窗內的內容區域,不包含工具欄、標籤欄等。也就是網頁實際顯示的區域。螢幕尺寸指的是裝置的物理顯示區域,使用者螢幕的整體大小。

 視口除錯工具

  在 IE 下,可使用 MS IE developer toolbar, Chrom 自帶的除錯工具也能很方便的進行視口除錯。Safari 使用者可選擇 ResizeMe 或 Resize, Firefox 使用者可以使用 Firesizer.

圖 2. IE Developer Toolbar 視口除錯截圖

IE Developer Toolbar 視口除錯截圖

圖 3. Firesizer 視口除錯工具截圖

Firesizer 視口除錯工具截圖

  響應式 Web 設計工作原理

  應用 CSS3 的媒體查詢(Media Queries),建立一個包含適應各種裝置尺寸樣式的 CSS。一旦頁面在特定的裝置上載入,此時,會先檢測裝置的視口大小,然後載入特定於裝置的樣式。即為不同的媒體型別設定專有的樣式表。

  建立媒體查詢

  以下程式碼演示了一個最為簡單的媒體查詢例項,瀏覽此頁面並不斷調整瀏覽器視窗寬度。頁面的背景顏色就會根據當前的視口尺寸而發生變化。CSS 屬性用於宣告如何表現頁面背景顏色切換,而 Media Query 語句是判斷輸出裝置的最大視口寬度是否滿足某種條件的條件表示式。

  清單 1. 基本媒體查詢程式碼

body {
background-color: grey;
}
@media screen and (max-width: 960px) {
body {
background-color: red;
}
}
@media screen and (max-width: 768px) {
body {
background-color: orange;
}
}
@media screen and (max-width: 550px) {
body {
background-color: yellow;
}
}
@media screen and (max-width: 320px) {
body {
background-color: green;
}
}

  目前 Firefox 3.6+、Safari 4+、Chrome 4+、Opera 9.5+、iOS Safari 3.2+、Opera Mobile 10+、Android 2.1,IE9+ 都支援媒體查詢。

圖 4. 相容 Media Query 的瀏覽器彙總

相容 Media Query 的瀏覽器彙總

  IE8 及以下的老版本並不支援 Media Query 查詢,但也可以引入 polyfill 指令碼(膩子指令碼 polyfill 就是一大堆五花八門技術的集合,目的就是填平舊瀏覽器對 HTML5、CSS3 支援上的缺陷),基於 JavaScript 實現相容修復, 引入 Respond.js(https://github.com/scottjehl/Respond)或 css3-mediaqueries.js(https://github.com/livingston/css3-mediaqueries-js)可以解決這個問題。

  清單 2. 為 IE 老版本引入膩子指令碼

<!--[if lt IE 9]> 
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> <![endif]-->


<!--[if lt IE 9]>  
<script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>  
<![endif]-->

 respond.js 和 css3-mediaqueries.js 的比較

  respond.js 介紹

  優勢:

  1. 體積小,速度快。
  2. 可靠!bootstrap 3 也引用了 respond.js。
  3. 不依賴其他指令碼或庫,併為移動端做了優化(respond.min.js 只有 1kb)

  劣勢:

  1. 僅支援 min-width 和 max-width。
  2. Respond.js 不解析通過@import 引用的 CSS 也不解析包含在 style 標籤內聯的 media queries,因為這些樣式不能重新請求解析。

  提示:

  1. 引用 respond.js 時,請放到所有 CSS 檔案之後(越早執行它,IE 使用者不容易看到非 media 內容的閃爍)
  2. respond.js 通過 Ajax 請求一個您的 CSS 的原始副本,如果您部署您的樣式檔案在 CDN 上(或者子域名下),您需要上傳一個代理頁面來實現跨域通訊。
  3. 因為安全的限制,一些瀏覽器可能不允許這個指令碼在 file://ruls 裡起作用(因為他使用 XMLHTTPRequest)。

  總結:它不是唯一的 CSS3 媒體查詢膩子指令碼,但是它可能是最快的。

  css3-mediaqueries.js 介紹

  優勢:

  1. 更健壯,支援很多 media query 特性,支援 px 和 em
  2. 實時響應

  劣勢:

  1. 體積較大(15kb) ,執行較慢
  2. 不支援 width
  3. 不支援 @import
  4. 對 <link> 和 <style> 標籤內的 media 屬性無效

  總結:當渲染複雜的響應性設計時,它能支援很多 media query,但執行明顯緩慢。

 CSS3 媒體查詢(Media Query)詳細介紹

  HTML4 和 CSS 2 中可以通過<link>標籤的 media 屬性為樣式表指定裝置型別,有八種,screen 和 print 是兩種最常見的媒體型別,舉例說明,以下程式碼為不同的裝置指定載入不同的樣式檔案,實際應用比如說,一個頁面在螢幕上顯示時使用無襯線字型,而在列印時則使用襯線字型以顯示更好的可讀性,或一個頁面在螢幕上顯示時有廣告,列印時去除廣告,都可通過 media 屬性來分別載入匹配的 CSS 檔案解決。

<link rel="stylesheet" type="text/css" media="screen" href="screen.css">

<link rel="stylesheet" type="text/css" media="print" href="print.css" />

  CSS3 中的 Media Queries 增加了更多的媒體查詢,在 CSS3 中我們可以設定不同型別的媒體條件,並根據對應的條件,給相應符合條件的媒體呼叫相對應的樣式表。您可以把媒體查詢語句想象為條件表示式,舉例說明:

<link rel="stylesheet" media="screen and (orientation: portrait)"  href="portraitscreen.css" />

  您是一塊縱向的螢幕嗎?

<link rel="stylesheet" media="not screen and (orientation: portrait)"  href="portraitscreen.css" />

  追加 not 顛倒該查詢的邏輯

<link rel="stylesheet" media="screen and (orientation: portrait) and (min-width:
800px)" href="800wide-portrait-screen.css" />

  視口寬度大於 800px 的縱向螢幕

<link rel="stylesheet" media="screen and (orientation: portrait) and (min-width:
800px), projection" href="800wide-portrait-screen.css" />

  只要是 projection 就為真,全部查詢都不為真,則不載入

@media screen and (max-device-width: 400px) {h1{color:red}

  媒體查詢也可以寫到樣式表中

@import url("phone.css") screen and (max-width:360px);

  也有不常見的寫法,是在 CSS 樣式表中用@import 在當前樣式表中引用其他樣式表。但需要注意的是慎用 CSS 的@import,會影響載入速度。

  關於 link vs @import 題外話

  我們可以通過 link 和@import 兩種方式引入 CSS 檔案

  清單 3. 引入 CSS 方式

<link rel='stylesheet' href='a.css'>

  或

<style>
@import url('a.css');
</style>

  二者之間的差別是:

  Link 採用 HTML 標籤將 CSS 關聯,而 import 可以在一個 CSS 檔案中引入其它的 CSS 檔案

  相容性的差別。IE6 以下不支援@import

  載入順序的差別(詳細請參見:http://www.stevesouders.com/blog/2009/04/09/dont-use-import/

  4)JS 控制 DOM 樣式時的差別(link 支援使用 Javascript 控制 DOM 去改變樣式;而@import 不支援)

  實際專案經驗是,@import 在 IE 中會導致檔案下載次序被更改,例如放置在@import 後面的 script 檔案會在 CSS 之前被下載執行,若此時指令碼里 getElementsByClassName 時則出錯。

 響應式設計前提

  響應式設計理念是基於流動佈局、彈性圖片、彈性表格、彈性視訊和媒體查詢等技術的組合。使用百分比佈局建立流動的彈性介面,同時使用媒體查詢來限制元素的變動範圍,這兩者組合到一起構成了響應式設計的核心。而固定寬度畫素的佈局無法實現多變的,未知的裝置。

  關於流動佈局,它是一種適應螢幕的做法,即不固定 DIV 的寬度,而是採用百分比作為單位來確定每一塊的寬度。具體採用的方式就是棄用 px,改用 em 或%為單位,早期我們此方式是為了文字縮放,確保老版本的 IE 也能調節字型大小。您可能會有疑問,既然現代瀏覽器很久以前就支援縮放以畫素為單位的文字,那麼用 em 的優越性又體現在哪裡呢?最大的優勢是,當我們用相對單位 em 來寫佈局和字型大小時,如果我們給<body>標籤設定文字大小為 100%,給其他文字都使用相對單位 em,那這些文字都會受 body 上的初始宣告的影響。這樣您可以批量修改頁面文字和佈局,相對更為靈活。缺點是可能在百分比的計算上不如畫素那樣簡單直接,將畫素轉為 em 的訣竅在於,Dan Cederholm 寫過一篇關於流式佈局裡文章裡提到一個公式,目標元素尺寸÷上下文元素尺寸=百分比尺寸,並不能簡單的把目標元素理解成子元素,把上下文元素理解成父級元素,雖然大多數時可以這麼理解,但上下文元素並不一定代表父級元素,舉例說明如下:

  如果一個實際 PSD 設計稿是採用固定畫素設計的,940px 的 header 層被包含在 960px 的 wrapper 層裡。

圖 5. PSD 設計稿舉例

PSD 設計稿舉例

  wrapper 層內包裹 header 層,按 px 寫法是:

  清單 4. 固定寬度設計程式碼示例

#wrapper {
margin-right: auto;
margin-left: auto;
width: 960px;
}
#header {
margin-right: 10px;
margin-left: 10px;
width: 940px;
}

  轉成百分比後,應該這麼寫,此時的上下文元素就是父級元素:

  清單 5. 百分比寬度設計程式碼示例

#wrapper {
margin-right: auto;
margin-left: auto;
width: 90%; /* 控制最外層的 div,這個值可以是 100%, 90%或者其它您認為實際頁面顯示最佳的一個百分比*/
}
#header {
margin-right: 10px;
margin-left: 10px;
width: 97.9166667%; /* 940 ÷ 960 */
}

  再舉例說明,如下 HTML 結構

<h1>測試<span>上下文</span></h1>

CSS 樣式為:
h1 {font-size: 4.3125em; } /* 69 ÷ 16 */
#content h1 span {
font-size: .550724638em; /* 38 ÷ 69 */
line-height: 1.052631579em; /* 40 ÷ 38 */
}

  預設瀏覽器文字大小是 16px,假設設計稿裡 h1 為 69px, span 為 38px,line-height 為 40px,可以看到<span>元素的文字大小(38px)是相對於其父元素的文字大小(69px)而言的,而它的行高(40px)則是相對於其本身的文字大小(38px)而言,所以我們不能一概而論認為上下文元素就是等同於父級元素。

  總結:流式佈局是響應式設計的基礎和起點。

 開始動手製作一個響應式網站吧

  以這樣一個頁面佈局為例,分別在最大寬度為 980px、700px 和 480px 時改變其佈局:

圖 6. 頁面佈局示例

頁面佈局示例

  第一步:Meta 標籤或@viewport{}

<meta name="viewport" content="width=device-width, initial-scale=1.0">

  Intial-scale=1.0 即阻止移動瀏覽器自動調整頁面大小 ,表示瀏覽器將按照其視口的實際大小來渲染頁面。

  我們也可以使用@viewport 規則控制 viewport,與使用 meta 標籤的效果相同,只是完全使用 CSS 來控制。zoom 描述符等同於 viewport meta 標籤的 initial-sacale 屬性。

@viewport {
width: device-width;
zoom: 1;
}

  第二步:為 IE8 和以下版本新增支援媒體查詢的 JS,可以用 media-queries.js 或 respond.js

<!--[if lt IE 9]>
<script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>
<![endif]-->

  第三步:編寫頁面 HTML 結構

/* STRUCTURE */
#pagewrap {
width: 960px;
}
#header {
height: 180px;
}
#content {
width: 600px;
float: left;
}
#sidebar {
width: 300px;
float: right;
}
#footer {
clear: both;
}

  第四步:編寫媒體查詢語句

  當視口寬度為 980px 及以下時定義了百分比寬度,當視口寬度為 700 及以下時,去除寬度和浮動,此時 content 和 sidebar 將佔滿整個寬度,當視口寬度為 480 及以下時,縮小 h1 標題的字型大小,隱藏 sidebar,以更好的適應小螢幕有限空間。程式碼如下:

/* for 980px or less */
@media screen and (max-width: 980px) {

#pagewrap {
width: 95%;
}
#content {
width: 65%;
}
#sidebar {
width: 30%;
}

}
/* for 700px or less */
@media screen and (max-width: 700px) {

#content {
width: auto;
float: none;
}
#sidebar {
width: auto;
float: none;
}

}

/* for 480px or less */
@media screen and (max-width: 480px) {

h1 {
font-size: 0.8em;
}
#sidebar {
display: none;
}

}

  (以上程式碼參考文章:http://webdesignerwall.com/tutorials/responsive-design-in-3-steps

 媒體查詢語句寫在哪最為合適?

  將不同的媒體查詢樣式儲存到獨立的檔案中,個人認為沒有太大的好處,因為多個獨立的檔案會增加用於頁面渲染的 HTTP 請求數量,從而導致頁面載入變慢,事實上這樣處理也並未更便於組織程式碼,而極容易遺漏部分媒體查詢語句。

  建議在已有的樣式表中追加媒體查詢樣式。在主樣式後面緊隨媒體查詢語句的一個好處是,當主樣式有所更改時,媒體查詢樣式很有可能也需要做相應的調整,這樣您不容易遺漏。如:

#header h1{}
@media screen and (max-width: 768px) {#header h1{}}方法。

窗體底端

 怎麼設定斷點?

  傳統的確定斷點的方案是使用一些固定的寬度進行劃分,如 320px(iPhone),768px(iPad),960px 或 1024px(傳統 PC 瀏覽器),這種方案的好處是很好照顧到了當前主流的裝置,但是技術發展實現是太快了,各種不同解析度的裝置層出不窮,比如一些手機尺寸接近平板,一些平板尺寸比電腦更大等等,很難保證未來能很好的支援各種裝置。另外一種確定斷點的方法是根據內容進行設定斷點以及設定多少個斷點。隨著各種尺寸裝置的出現,斷點命名採用更為通用的方式,而不是用裝置來命名更為合適。

圖 7. 斷點設定參考

斷點設定參考

 響應式圖片

  實現圖片隨著流動佈局相應縮放非常簡單。需要在 CSS 中宣告:

img { max-width: 100%; }

  這樣就可以使圖片自動縮放到與其容器 100%匹配。我們可以將同樣的樣式應用到其他多媒體標籤上。如:

img,object,video,embed {max-width: 100%;}

  圖片可以隨著視口的伸縮而縮放了,但是如果將視口拉大(比如 1900px),直到圖片拉伸至超出其原始尺寸,那麼圖片很有可能也被拉寬,必須追加一句 CSS 宣告:

.img{max-width: 202px;}

 我們也可以給最外層#wrapper 來設定 max-width 來限制流體佈局頁面被拉大,如:

  清單 6. 響應式圖片程式碼示例

#wrapper {
margin-right: auto;
margin-left: auto;
width: 96%;
max-width: 1414px;
}

  那麼問題來了?這樣算完成了圖片的響應嗎?答案是否定的。彈性圖片並不等於響應式圖片。我們應該為不同的螢幕尺寸提供不同的圖片。如下所示,不再是一張圖片滿足不同的裝置,而是為大螢幕準備大尺寸圖片,小螢幕準備尺寸更小的清晰圖片。

圖 8. 一張圖片應用在不同尺寸的裝置上

一張圖片應用在不同尺寸的裝置上

圖 9. 針對不同的裝置應用不同的圖片

針對不同的裝置應用不同的圖片

 推薦二種響應式圖片解決方案如下:

  Matt Wilcox 解決方案

  1. 把.htaccess 和 adaptive-images.php 放根目錄
  2. 建立一個可寫入的快取資料夾
  3. <script>document.cookie='resolution='+Math.max(screen.width,screen.height)+'; path=/';</script>
Sencha.io Src解決方案:

<img src="http://src.sencha.io/http://mysite.com/images/my-image.jpg" />

 響應式視訊

  不同與以往需要插入視訊需要一段臃腫的程式碼,HTML5 插入視訊只需要一行程式碼,但問題是它不是響應的。

<video src="Video.ogg"></video>

  注意:Safari 只允許在<video>和<audio>元素中使用 MP4/H.264/AAC 媒體檔案,而 Firefox 和 Opera 則只支援 Ogg 和 WebM,所以更為完整的寫法如下:

  清單 7. 響應式視訊程式碼示例

<video width="640" height="480" controls autoplay preload="auto" loop
poster="myVideoPoster.jpg">
<source src="video/myVideo.ogv" type="video/ogg">
<source src="video/myVideo.mp4" type="video/mp4">
responsive video
</video>

  如何讓視訊響應呢?我們需要追加 max-width:100%宣告:

video { max-width: 100%; height: auto; }

  問題:如果視訊是被 iframe 內嵌又如何實現響應式呢?最簡單的辦法是使用一個名為 FitVids 的 jQuery 小外掛。程式碼如下:

  清單 8. Iframe 引入的視訊實現響應式程式碼示例

<script src="js/fitvids.js"></script>

<script>
$(document).ready(function(){
$("#content").fitVids();
});
</script>

 響應式表格

  實現資料表格響應的方式有很多種,要根據表格內容,資料量來進行具體的設計。流體表格並不等於響應式表格,比如一個百分比寬度表格,在小螢幕裝置上可以正常顯示但內容整體被壓縮得較小,可讀性差,並不代表它是真正響應的。

  舉例說明,針對以下這個資料較多的表格,有多種設計思路可以採用。

圖 10. 如何實現一個響應式的複雜表格之表格示例

如何實現一個響應式的複雜表格之表格示例

  思路1:為小螢幕隱藏不必要的列,精簡表格。主要利用 CSS table td:nth-child(n){display:none}實現。

  思路 2:將橫向的表頭利用 CSS 改為縱向顯示並固定位置,其餘內容部分不變並出現橫向滾動條。tbody 上應用 white-space:nowrap; tbody tr 下應用 display:inline-block;

  思路 3:將每一行資料對應表頭顯示在一塊區域內,接下來每行依次類推。利用 HTML data 屬性,將表頭名稱寫到 CSS 中,td:before{content:attr(data-title);

  思路 4:將純文字的表格在小螢幕上的餅圖或柱狀圖,以一種更豐富的形式顯示資料,前提是這是合適表格內容的。

  思路 5:用一張小縮圖顯示在小螢幕上並提示使用者點選檢視錶格,從而新開頁面以獲得更大的螢幕空間顯示整個表格。

  以上解決方案具體實現程式碼請參考“參考資源”連結。

 響應式設計推薦框架

  使用 Modernizr 讓老版本 IE 支援 HTML5 元素,BootStrap, Semantic UI, Foundation 前端介面開發框架都可選擇。

 總結

  本文簡單介紹了常用的響應式設計工具,思路和技巧,除了需要掌握一定的技術實現手段,更需要有如何設計,如何佈局的思考,也不能忽略對高解析度裝置的支援,瞭解漸進增強與優雅降級的本質區別,真正實現頁面好看、好用、合理。

相關文章