? ? ? 寫在前面的話:對于移動Web App來說,響應式設計相當的有價值,現在大家也正在逐漸的了解它。但是我認為它也有自己適用的范圍,需要根據具體的場景來選擇使用。正好最近業界對此也有一些聲音和反思傳遞,例如我之前的一篇博文《[用HTML5實現iPad應用無限平滑滾動](http://blog.csdn.net/hfahe/article/details/7535914)》里就有提及。現在我翻譯一篇相關文章,大家可以對此有更多的了解和判斷。-- 宇捷
**媒介查詢很偉大,但是...**
? ? ? 對于Web開發人員來說,如果要通過對樣式表進行微調來為不同尺寸設備的用戶提供更好的體驗,媒介查詢(Media Queries)非常棒。?媒介查詢實質上可以根據屏幕的尺寸來自定義網站的CSS。在你深入這篇文章之前,可以更多的了解[響應式網頁設計](http://www.html5rocks.com/mobile/responsivedesign)(還記得《[用3個步驟實現響應式網頁設計](http://blog.csdn.net/hfahe/article/details/7082718/)》這篇文章嗎?)?,并且看看使用媒介查詢的一些好例子:?[mediaqueri.es](http://mediaqueri.es/)?。
? ? ??像布拉德·弗羅斯特在[以前文章](http://bradfrostweb.com/blog/web/responsive-web-design-missing-the-point/)中指出的一樣,調整界面只是構建移動Web App時需要考慮的眾多事情之一。?如果你在構建移動Web App時只通過媒介查詢自定義了布局,那么我們會有以下的問題:
- 所有的設備都采用同樣的JavaScript、CSS以及內容(圖片、視頻等),導致產生比預期更長的加載時間。
- 所有的設備都有相同的初始DOM結構,可能迫使開發人員編寫過于復雜的CSS樣式。
- 對于為每個設備指定自定義的交互來說缺乏彈性。
**除媒介查詢外,Web APP還需要更多**
? ? ??不要誤會我的意思。我并不是討厭通過媒介查詢進行響應式設計,并絕對認為它占有一席之地。此外,上述的一些問題可以通過例如[響應式圖像](http://www.alistapart.com/articles/responsive-images-how-they-almost-worked-and-what-we-need/)?,動態腳本加載等來解決。但是就某一點而言,你也許會發現自己做了太多的增量調整,而可能提供不同的版本效果會更佳。
? ? ??當構建的界面在復雜性方面有所增加,同時被單頁的Web App所吸引,你會想要為每個設備類型自定義用戶界面做更多事情。本文將教你如何用最少的努力實現這樣的自定義。通用的方法包括將訪問的設備劃分到正確的分類,并且為該設備提供合適的版本,同時最大限度地提高代碼在版本之間的重用。
**針對哪些設備類型?**
? ? ??現在有成千上萬的互聯網設備,幾乎每一個都有瀏覽器。復雜之處在于它們的差異性:蘋果筆記本,Windows工作站,有觸摸輸入、滾輪、鍵盤和語音輸入的iPhone手機,iPad和Android手機,帶壓力傳感器的設備,智能手表,烤面包機以及冰箱等等。它們無處不在,而且有些非常罕見。

各種各樣的設備([來源](http://www.flickr.com/photos/brad_frost/6164723945/in/set-72157627712478230/))
? ? ??為了創造良好的用戶體驗,你需要知道誰是你的用戶以及他們使用的是什么設備。如果你為桌面用戶創建了一個使用鼠標和鍵盤的界面,并將它展示給智能手機用戶,這將是一個極大的失敗,因為它設計在另一個屏幕大小和輸入方式之上。
? ? ??這里有兩種極端的方法:
1.???創建一個為所有設備工作的版本。用戶體驗將因此受到影響,因為不同的設備有不同的設計考慮。
2.???為每一個要支持的設備各自創建一個版本。這個工作將永遠進行下去,因為你將為你的應用構建太多版本。此外,當新的智能手機誕生(大約每周都有)時,你將被??迫再次創建一個版本。
? ? ??這里有一個基本的權衡:有更多的設備類別時,你可以提供更好的用戶體驗,但是需要做更多設計,實現和維護的工作。
? ? ??為每種設備創建單獨的版本對于性能原因來說也許是一個好辦法,或者你想為不同的設備創建的版本差異甚巨。否則,?[響應式網頁設計](http://www.html5rocks.com/mobile/responsivedesign)會是完全合理的做法。
**一個潛在的方案**
這里有一個妥協方案:將設備分類,并為每個種類提供最佳體驗。選擇什么類別取決于你的產品和目標用戶。下面是一個示例,能夠很好的跨越現今流行的網絡設備。
1.????小屏幕+觸摸(主要是手機)
2.????大屏幕+觸摸(主要是平板)
3.????大屏幕+鍵盤/鼠標(主要是臺式機/筆記本電腦)
? ? ??這只是許多可能的分類方式之一,但在寫作時有很大的意義。上面的列表中缺少的是沒有觸摸屏的移動設備(例如功能手機,一些專用的電子書閱讀器)。然而,這些設備大部分都有鍵盤或者屏幕閱讀軟件,如果你的站點精心設計,可以在上面工作良好。
**特定外形的WEB App例子**
? ? ??有許多針對不同因素提供不同Web服務版本的例子。谷歌搜索是這樣,Facebook也是。這主要是考慮了到性能(獲取資源,渲染頁面)和更通用的用戶體驗。
? ? ??在Native App的世界里,許多開發者選擇為不同種類的設備設計產品。?例如,Flipboard iPad版本的UI與iPhone版本差異很大。平板版本為雙手使用和水平旋轉進行了優化,而手機版本關注單手交互和垂直翻轉的體驗。許多其他的iOS應用在手機和平板上也有明顯的不同,例如[Things](http://culturedcode.com/things/)(Todo list)和如下所示的?[Showyou](http://showyou.com/)?(社會化視頻):

針對手機和平板定制的UI
**方法#1:服務器端檢測**
? ? ??在服務器端,我們要了解正在處理的設備有更多的限制。每次請求發送的User-Agent頭所提供的user agent(用戶代理)字符串可能是最有用的線索。正因為如此,相同UA的嗅探方法會產生作用。事實上,DeviceAtlas和WURFL項目已經開始這樣做了(并提供了一大堆設備有關的其他信息)。
? ? ??不幸的是目前這些項目都存在挑戰。WURFL非常龐大,包含20MB的XML,可能為每個請求導致明顯的服務器開銷。有項目因為性能方面的原因分割了這些XML。DeviceAtlas并不開源,需要付費使用。
? ? ??這里有更簡單,而且免費的替代品,例如[檢測移動瀏覽器](http://detectmobilebrowsers.com/)項目。當然,缺點是設備檢測難免會不夠全面。?此外,它只區分移動和非移動設備,以及通過[ad-hoc軟件](http://detectmobilebrowsers.com/about)提供有限的平板支持。
**方法2:客戶端檢測**
? ? ??使用特性檢測,我們可以了解更多用戶瀏覽器和設備的信息。我們需要確定的要點是,該設備是否具有觸摸功能,以及它的屏幕是大是小。
? ? ??我們需要畫一條線來區分屏幕大和小的觸摸設備。例如像5寸Galaxy Note的邊緣情況。下圖顯示了許多流行的Andr??oid和iOS設備輪廓(附上相應的屏幕分辨率)。星號表示該設備可以支持雙倍密度。雖然像素密度可能會增加一倍,CSS仍然會報告相同的大小。
? ? ??對CSS里像素點的快速介紹:手機Web頁面上的CSS像素和PC上并[不一樣](http://www.quirksmode.org/blog/archives/2010/04/a_pixel_is_not.html)。iOS視網膜設備引入了雙倍像素密度(例如iPhone 3GS對iPhone 4,iPad 2對iPad 3)。視網膜設備上Safari瀏覽器的用戶代理仍然報告相同的設備寬度,以免破壞網頁。當其它設備(例如Android)采用了更高分辨率的顯示屏時,它們也采用了相當的解決方案。

設備的分辨率
? ? ??這種方式會更復雜,但是這對考慮同時兼容縱向和橫向模式非常重要。我們不希望每次屏幕旋轉時都重新加載頁面或者加載額外的腳本,雖然我們可能要呈現不同的頁面。
下圖中,正方形代表每個設備的最大尺寸,是疊加了縱向和橫向輪廓的結果:

橫向+縱向分辨率
? ? ??通過將閾值設置為650px?,我們將iPhone,Galaxy Nexus分類為小觸摸屏設備,而將iPad,Galaxy Tab分類為“平板”。跨界的Galaxy Note在這種情況下被歸類為“手機”,將采用手機布局。
? ? ??所以,一個合理的策略可能看起來像下面這樣:
~~~
if (hasTouch) {
if (isSmall) {
device = PHONE;
} else {
device = TABLET;
}
} else {
device = DESKTOP;
}
~~~
? ? ??趕快看看一個小的示例[特性檢測方法](http://www.html5rocks.com/static/demos/cross-device/feature/index.html)吧。
? ? ??另一種方法是使用用戶代理嗅探來檢測設備類型,基本上就是創建一套試探方法來匹配用戶的navigator.userAgent。偽代碼看起來像這樣:
~~~
var ua = navigator.userAgent;
for (var re in RULES) {
if (ua.match(re)) {
device = RULES[re];
return;
}
}
~~~
? ? ??馬上來看看一個示例-[UA檢測方法](http://www.html5rocks.com/static/demos/cross-device/ua/index.html)。
**在客戶端加載的說明**
? ? ??如果你正在服務器上檢測用戶代理,你可以在收到新請求時決定提供哪種CSS,JavaScript和DOM節點。然而,如果你正在采用客戶端檢測,情況則更為復雜。你有如下幾種選擇:
1.????重定向到特定設備類型的URL,其??中包含該設備類型的版本。
2.????動態加載設備特定類型的內容。
? ? ??第一種方法很簡單,需要采用window.location.href = '/tablet'這種重定向的方式。然而,URL地址會附加設備類型的信息,所以你可能想使用HTML5的[歷史API](http://diveintohtml5.info/history.html)來清理網址。不幸的是,這種方法涉及一個重定向,所以可能會很慢,尤其是在移動設備上。
? ? ??第二種方法實現更加復雜。你需要一種機制來動態加載CSS和JS,還有(根據瀏覽器而定)你可能無法實現例如自定義<meta viewport>?這樣的事。此外因為沒有重定向,你需要在一張頁面上來響應請求。當然,你可以用JavaScript來實現,但是這可能導致性能緩慢和/或糟糕的代碼,這一切都取決于你的應用程序。
**選擇客戶端或服務器方案**
? ? ??下面是在這些方法之間的權衡:
**選擇客戶端**?:
- 基于屏幕尺寸或可擴展性的方案和用戶代理比起來更為長遠。
- 無需不斷更新用戶代理名單。
**選擇服務器**?:
- 能完全控制什么設備上加載什么版本。
- 更好的性能:無需客戶端重定向或動態加載。
? ? ??我個人的偏好是,最開始使用device.js和客戶端檢測。?隨著應用的發展,如果發現客戶端重定向有明顯的性能問題,你可以很容易地刪除device.js腳本,并在服務器上執行用戶代理檢測。
**DEVICE.JS介紹**
? ? ??device.js是一個起點,這樣做基于語義,依靠媒介查詢進行設備檢測,從而無需特殊的服務器端配置,節省了需要實現用戶代理字符串解析的時間和精力。
? ? ??這個方法是在<head>標簽的頂部用搜索引擎友好的標記([linkrel=alternate](http://blog.whatwg.org/the-road-to-html-5-link-relations#rel-alternate))聲明你要提供的網站版本。
~~~
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
~~~
? ? ??接下來,你可以采用服務器端UA檢測和版本重定向,或者使用device.js腳本來執行基于功能的客戶端重定向。
? ? ??更多詳細信息,請參閱[device.js項目](https://github.com/borismus/device.js)頁面?,同時還有一個使用了device.js進行客戶端重定向的[測試應用](http://borismus.github.com/device.js/sample/)。
**建議:MVC的具體視圖**
? ? ??現在你可能會想,我告訴你的是建立三個完全獨立的應用程序,每個用于一種設備類型。不!?代碼共享是關鍵。
? ? ??希望你已經使用了一個類MVC的框架,例如Backbone,Ember等等。如果你已經熟悉重點分解的原則,尤其是你的用戶界面(視圖層)應該與邏輯(模型層)分離。如果你對此還比較陌生,可以開始了解[MVC的一些資源](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)和[JavaScript中的MVC](http://addyosmani.github.com/todomvc/)?模式。
? ? ??跨設備非常適合現有的MVC框架。你可以輕松地移動視圖到獨立的文件,為每個設備類型創建一個自定義視圖。然后你就可以為所有設備使用除了視圖層之外同樣的代碼。

跨設備的MVC模式
? ? ??你的項目可能有以下的結構(當然,你可以自由選擇對你應用最有意義的結構):
~~~
models/ (shared models)
item.js
item-collection.js
controllers/ (shared controllers)
item-controller.js
versions/ (device-specific stuff)
tablet/
desktop/
phone/ (phone-specific code)
style.css
index.html
views/
item.js
item-list.js
~~~
? ? ??這種結構使你能夠完全控制每個版本加載哪些內容,因為你必須為每個設備采用自定義的HTML,CSS和JavaScript。這非常強大,是開發跨端Web App最精簡和最有效的方式,不會依賴于一些小的技巧,例如自適應圖像。
? ? ??一旦你運行喜歡的構建工具,會把所有的Javascript和CSS合并和壓縮到一個獨立的文件里,以實現更快的加載速度,而輸出的HTML頁面看起來類似以下的形式(在手機上,使用device.js):
~~~
<!doctype html>
<head>
<title>Mobile Web Rocks! (Phone Edition)</title>
<!-- Every version of your webapp should include a list of all
versions. -->
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
<link rel="alternate" href="http://m.foo.com" id="phone"
media="only screen and (max-device-width: 650px)">
<link rel="alternate" href="http://tablet.foo.com" id="tablet"
media="only screen and (min-device-width: 650px)">
<!-- Viewport is very important, since it affects results of media
query matching. -->
<meta name="viewport" content="width=device-width">
<!-- Include device.js in each version for redirection. -->
<script src=”device.js”></script>
<link rel=”style” href=”phone.min.css”>
</head>
<body>
<script src=”phone.min.js”></script>
</body>
~~~
? ? ??需要注意的是(touch-enabled: 0)媒介查詢并不標準(只有Firefox通過moz前綴實現了),但是能夠被device.js正確運行(感謝[Modernizr.touch](http://modernizr.com/))。
**版本覆蓋**
? ? ??設備檢測有時候有誤,在某些情況下,用戶可能更喜歡在手機上采用平板布局(也許他們正在使用Galaxy Note),所以一定要向用戶提供版本的選擇。
? ? ??通常的做法是提供一個從桌面到移動版本的鏈接。這很容易實現,device.js通過device的GET參數來支持此功能。
**結論**
? ? ??綜上,當需要建立跨設備單頁的用戶界面時,并不適合響應式設計,我們可以這樣做:
1.????挑選一系列設備分類進行支持,并為設備分類設定標準。
2.????建立你的MVC應用,把界面從代碼庫分離出來。
3.????使用[device.js](https://github.com/borismus/device.js)進行客戶端設備分類檢測。
4.????當你準備好了時,為每個設備分類打包你的腳本和樣式表。
5.????如果客戶端重定向有性能問題,放棄device.js,并換到服務器端做UA檢測。
譯自:[http://www.html5rocks.com/en/mobile/cross-device/](http://www.html5rocks.com/en/mobile/cross-device/)
轉載請注明:來自[蔣宇捷的博客](http://blog.csdn.net/hfahe)
- 前言
- AutoPager的簡單實現
- 利用CSS3特性巧妙實現漂亮的DIV箭頭
- IE9在Win7下任務欄新特性簡介
- 瀏覽器九宮格的簡單實現
- Raphael js庫簡介
- 使用CSS3構建Ajax加載動畫
- 用CSS3創建動畫價格表
- 用CSS3實現瀏覽器的縮放功能
- 用純CSS3實現QQ LOGO
- 用CSS3創建旋轉載入器
- 使用Javascript開發移動應用程序
- 用HTML5創建超酷圖像灰度漸變效果
- 使用CSS3創建文字顏色漸變(CSS3 Text Gradient)
- 僅用CSS創建立體旋轉幻燈片
- 如何創建跨瀏覽器的HTML5表單
- 用CSS3實現動畫進度條
- HTML5 Guitar Tab Player
- 奇妙的HTML5 Canvas動畫實例
- 談HTML5和CSS3的國際化支持
- 實現跨瀏覽器的HTML5占位符
- 前端開發必備工具:WhatFont Bookmarklet-方便的查詢網頁上的字體
- 使用HTML5和CSS3來創建幻燈片
- HTML5之美
- 如何使用HTML5創建在線精美簡歷
- 以小見大、由淺入深-談如何面試Javascript工程師
- 快速入門:HTML5強大的Details元素
- 用CSS3實現圖像風格
- HTML5視頻字幕與WebVTT
- 用純CSS3實現Path華麗動畫
- 用3個步驟實現響應式網頁設計
- 遇見CSS3濾鏡
- 關于CSS3濾鏡的碎念
- 用純CSS3繪制萌系漫畫人物動態頭像
- CSS3新的鼠標樣式介紹
- 用HTML5獻上愛的3D玫瑰
- 對HTML5 Device API相關規范的解惑
- 如何使用HTML5實現拍照上傳應用
- 2012第一季度國外HTML5移動開發趨勢
- HTML5新特性:范圍樣式
- 百度開發者大會-《用HTML5新特性開發移動App》PPT分享
- Chrome 19對于HTML5最新支持的動態:電池狀態API,全屏API,震動API,語音API
- 遇見Javascript類型數組(Typed Array)
- 用HTML5 Audio API開發游戲音樂
- 用HTML5實現人臉識別
- 用Javascript實現人臉美容
- Chrome 20對于HTML5最新支持的動態:顏色輸入,網絡信息API,CSS著色器
- 用HTML5實現手機搖一搖的功能
- 用HTML5實現iPad應用無限平滑滾動
- 用非響應式設計構建跨端Web App
- 了解SVG
- HTML5圖像適配介紹
- HTML5安全:內容安全策略(CSP)簡介
- HTML5安全:CORS(跨域資源共享)簡介
- 用CSS3 Region和3D變換實現書籍翻頁效果
- 談談移動App的思維誤區
- Chrome新特性:文件夾拖拽支持
- 《關注HTML5安全》
- HTML5安全風險詳析之一:CORS攻擊
- HTML5安全風險詳析之二:Web Storage攻擊
- HTML5圖像適配最新進展:響應式圖片規范草案
- HTML5移動Web App相關標準狀態及路線圖
- HTML5安全風險詳析之三:WebSQL攻擊
- Chrome引入WebRTC支持視頻聊天App
- HTML5安全風險詳析之四:Web Worker攻擊
- HTML5安全風險詳析之五:劫持攻擊
- HTML5安全風險詳析之六:API攻擊
- HTML5安全攻防詳析之七:新標簽攻擊
- 在iOS Safari中播放離線音頻
- 使用WebRTC實現遠程屏幕共享
- Firefox、Android、iOS遇見WebRTC
- HTML5光線傳感器簡介
- HTML5安全攻防詳析之八:Web Socket攻擊
- HTML5安全攻防詳析之完結篇:HTML5對安全的改進
- 激動人心!在網頁上通過語音輸入文字 - HTML5 Web Speech API介紹
- Web滾動性能優化實戰
- 用CSS3設計響應式導航菜單
- 用HTML5構建高性能視差網站
- 漫談@supports與CSS3條件規則
- HTML5下載屬性簡介
- 如何開發優秀的HTML5游戲?-迪斯尼《尋找奧茲之路》游戲技術詳解(一)
- 如何開發優秀的HTML5游戲?-迪斯尼《尋找奧茲之路》游戲技術詳解(二)
- 趨勢:Chrome為打包應用提供強大新特性
- 從HTML5移動應用現狀談發展趨勢
- 基于HTML5的Web跨設備超聲波通信方案