非響應(yīng)式設(shè)計(jì)構(gòu)建跨端Web App
對(duì)于Web開(kāi)發(fā)人員來(lái)說(shuō),如果要通過(guò)對(duì)樣式表進(jìn)行微調(diào)來(lái)為不同尺寸設(shè)備的用戶提供更好的體驗(yàn),媒體查詢(Media Queries)非常棒。 媒體查詢實(shí)質(zhì)上可以根據(jù)屏幕的尺寸來(lái)自定義網(wǎng)站的CSS。在你深入這篇文章之前,可以更多的了解響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)(還記得《用3個(gè)步驟實(shí)現(xiàn)響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)》這篇文章嗎?) ,并且看看使用媒介查詢的一些好例子: mediaqueri.es 。
像布拉德·弗羅斯特在以前文章中指出的一樣,調(diào)整界面只是構(gòu)建移動(dòng)Web App時(shí)需要考慮的眾多事情之一。 如果你在構(gòu)建移動(dòng)Web App時(shí)只通過(guò)媒介查詢自定義了布局,那么我們會(huì)有以下的問(wèn)題:
所有的設(shè)備都采用同樣的JavaScript、CSS以及內(nèi)容(圖片、視頻等),導(dǎo)致產(chǎn)生比預(yù)期更長(zhǎng)的加載時(shí)間。
所有的設(shè)備都有相同的初始DOM結(jié)構(gòu),可能迫使開(kāi)發(fā)人員編寫過(guò)于復(fù)雜的CSS樣式。
對(duì)于為每個(gè)設(shè)備指定自定義的交互來(lái)說(shuō)缺乏彈性。
除媒介查詢外,Web APP還需要更多
不要誤會(huì)我的意思。我并不是討厭通過(guò)媒介查詢進(jìn)行響應(yīng)式設(shè)計(jì),并絕對(duì)認(rèn)為它占有一席之地。此外,上述的一些問(wèn)題可以通過(guò)例如響應(yīng)式圖像 ,動(dòng)態(tài)腳本加載等來(lái)解決。但是就某一點(diǎn)而言,你也許會(huì)發(fā)現(xiàn)自己做了太多的增量調(diào)整,而可能提供不同的版本效果會(huì)更佳。
當(dāng)構(gòu)建的界面在復(fù)雜性方面有所增加,同時(shí)被單頁(yè)的Web App所吸引,你會(huì)想要為每個(gè)設(shè)備類型自定義用戶界面做更多事情。本文將教你如何用最少的努力實(shí)現(xiàn)這樣的自定義。通用的方法包括將訪問(wèn)的設(shè)備劃分到正確的分類,并且為該設(shè)備提供合適的版本,同時(shí)最大限度地提高代碼在版本之間的重用。
針對(duì)哪些設(shè)備類型?
現(xiàn)在有成千上萬(wàn)的互聯(lián)網(wǎng)設(shè)備,幾乎每一個(gè)都有瀏覽器。復(fù)雜之處在于它們的差異性:蘋果筆記本,Windows工作站,有觸摸輸入、滾輪、鍵盤和語(yǔ)音輸入的iPhone手機(jī),iPad和Android手機(jī),帶壓力傳感器的設(shè)備,智能手表,烤面包機(jī)以及冰箱等等。它們無(wú)處不在,而且有些非常罕見(jiàn)。
各種各樣的設(shè)備
為了創(chuàng)造良好的用戶體驗(yàn),你需要知道誰(shuí)是你的用戶以及他們使用的是什么設(shè)備。如果你為桌面用戶創(chuàng)建了一個(gè)使用鼠標(biāo)和鍵盤的界面,并將它展示給智能手機(jī)用戶,這將是一個(gè)極大的失敗,因?yàn)樗O(shè)計(jì)在另一個(gè)屏幕大小和輸入方式之上。
這里有兩種極端的方法:
1. 創(chuàng)建一個(gè)為所有設(shè)備工作的版本。用戶體驗(yàn)將因此受到影響,因?yàn)椴煌脑O(shè)備有不同的設(shè)計(jì)考慮。
2. 為每一個(gè)要支持的設(shè)備各自創(chuàng)建一個(gè)版本。這個(gè)工作將永遠(yuǎn)進(jìn)行下去,因?yàn)槟銓槟愕膽?yīng)用構(gòu)建太多版本。此外,當(dāng)新的智能手機(jī)誕生(大約每周都有)時(shí),你將被迫再次創(chuàng)建一個(gè)版本。
這里有一個(gè)基本的權(quán)衡:有更多的設(shè)備類別時(shí),你可以提供更好的用戶體驗(yàn),但是需要做更多設(shè)計(jì),實(shí)現(xiàn)和維護(hù)的工作。
為每種設(shè)備創(chuàng)建單獨(dú)的版本對(duì)于性能原因來(lái)說(shuō)也許是一個(gè)好辦法,或者你想為不同的設(shè)備創(chuàng)建的版本差異甚巨。否則, 響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)會(huì)是完全合理的做法。
一個(gè)潛在的方案
這里有一個(gè)妥協(xié)方案:將設(shè)備分類,并為每個(gè)種類提供最佳體驗(yàn)。選擇什么類別取決于你的產(chǎn)品和目標(biāo)用戶。下面是一個(gè)示例,能夠很好的跨越現(xiàn)今流行的網(wǎng)絡(luò)設(shè)備。
1. 小屏幕+觸摸(主要是手機(jī))
2. 大屏幕+觸摸(主要是平板)
3. 大屏幕+鍵盤/鼠標(biāo)(主要是臺(tái)式機(jī)/筆記本電腦)
這只是許多可能的分類方式之一,但在寫作時(shí)有很大的意義。上面的列表中缺少的是沒(méi)有觸摸屏的移動(dòng)設(shè)備(例如功能手機(jī),一些專用的電子書閱讀器)。然而,這些設(shè)備大部分都有鍵盤或者屏幕閱讀軟件,如果你的站點(diǎn)精心設(shè)計(jì),可以在上面工作良好。
#p#
特定外形的WEB App例子
有許多針對(duì)不同因素提供不同Web服務(wù)版本的例子。谷歌搜索是這樣,Facebook也是。這主要是考慮了到性能(獲取資源,渲染頁(yè)面)和更通用的用戶體驗(yàn)。
在Native App的世界里,許多開(kāi)發(fā)者選擇為不同種類的設(shè)備設(shè)計(jì)產(chǎn)品。 例如,F(xiàn)lipboard iPad版本的UI與iPhone版本差異很大。平板版本為雙手使用和水平旋轉(zhuǎn)進(jìn)行了優(yōu)化,而手機(jī)版本關(guān)注單手交互和垂直翻轉(zhuǎn)的體驗(yàn)。許多其他的iOS應(yīng)用在手機(jī)和平板上也有明顯的不同,例如Things(Todo list)和如下所示的 Showyou (社會(huì)化視頻):
針對(duì)手機(jī)和平板定制的UI
方法#1:服務(wù)器端檢測(cè)
在服務(wù)器端,我們要了解正在處理的設(shè)備有更多的限制。每次請(qǐng)求發(fā)送的User-Agent頭所提供的user agent(用戶代理)字符串可能是最有用的線索。正因?yàn)槿绱?,相?/span>UA的嗅探方法會(huì)產(chǎn)生作用。事實(shí)上,DeviceAtlas和WURFL項(xiàng)目已經(jīng)開(kāi)始這樣做了(并提供了一大堆設(shè)備有關(guān)的其他信息)。
不幸的是目前這些項(xiàng)目都存在挑戰(zhàn)。WURFL非常龐大,包含20MB的XML,可能為每個(gè)請(qǐng)求導(dǎo)致明顯的服務(wù)器開(kāi)銷。有項(xiàng)目因?yàn)樾阅芊矫娴脑蚍指盍诉@些XML。DeviceAtlas并不開(kāi)源,需要付費(fèi)使用。
這里有更簡(jiǎn)單,而且免費(fèi)的替代品,例如檢測(cè)移動(dòng)瀏覽器項(xiàng)目。當(dāng)然,缺點(diǎn)是設(shè)備檢測(cè)難免會(huì)不夠全面。 此外,它只區(qū)分移動(dòng)和非移動(dòng)設(shè)備,以及通過(guò)ad-hoc軟件提供有限的平板支持。
方法2:客戶端檢測(cè)
使用特性檢測(cè),我們可以了解更多用戶瀏覽器和設(shè)備的信息。我們需要確定的要點(diǎn)是,該設(shè)備是否具有觸摸功能,以及它的屏幕是大是小。
我們需要畫一條線來(lái)區(qū)分屏幕大和小的觸摸設(shè)備。例如像5寸Galaxy Note的邊緣情況。下圖顯示了許多流行的Android和iOS設(shè)備輪廓(附上相應(yīng)的屏幕分辨率)。星號(hào)表示該設(shè)備可以支持雙倍密度。雖然像素密度可能會(huì)增加一倍,CSS仍然會(huì)報(bào)告相同的大小。
對(duì)CSS里像素點(diǎn)的快速介紹:手機(jī)Web頁(yè)面上的CSS像素和PC上并不一樣。iOS視網(wǎng)膜設(shè)備引入了雙倍像素密度(例如iPhone 3GS對(duì)iPhone 4,iPad 2對(duì)iPad 3)。視網(wǎng)膜設(shè)備上Safari瀏覽器的用戶代理仍然報(bào)告相同的設(shè)備寬度,以免破壞網(wǎng)頁(yè)。當(dāng)其它設(shè)備(例如Android)采用了更高分辨率的顯示屏?xí)r,它們也采用了相當(dāng)?shù)慕鉀Q方案。
設(shè)備的分辨率
這種方式會(huì)更復(fù)雜,但是這對(duì)考慮同時(shí)兼容縱向和橫向模式非常重要。我們不希望每次屏幕旋轉(zhuǎn)時(shí)都重新加載頁(yè)面或者加載額外的腳本,雖然我們可能要呈現(xiàn)不同的頁(yè)面。
下圖中,正方形代表每個(gè)設(shè)備的最大尺寸,是疊加了縱向和橫向輪廓的結(jié)果:
橫向+縱向分辨率
通過(guò)將閾值設(shè)置為650px ,我們將iPhone,Galaxy Nexus分類為小觸摸屏設(shè)備,而將iPad,Galaxy Tab分類為“平板”。跨界的Galaxy Note在這種情況下被歸類為“手機(jī)”,將采用手機(jī)布局。
所以,一個(gè)合理的策略可能看起來(lái)像下面這樣:
- if (hasTouch) {
- if (isSmall) {
- device = PHONE;
- } else {
- device = TABLET;
- }
- } else {
- device = DESKTOP;
- }
趕快看看一個(gè)小的示例特性檢測(cè)方法吧。
另一種方法是使用用戶代理嗅探來(lái)檢測(cè)設(shè)備類型,基本上就是創(chuàng)建一套試探方法來(lái)匹配用戶的navigator.userAgent。偽代碼看起來(lái)像這樣:
- var ua = navigator.userAgent;
- for (var re in RULES) {
- if (ua.match(re)) {
- device = RULES[re];
- return;
- }
- }
馬上來(lái)看看一個(gè)示例-UA檢測(cè)方法。
#p#
在客戶端加載的說(shuō)明
如果你正在服務(wù)器上檢測(cè)用戶代理,你可以在收到新請(qǐng)求時(shí)決定提供哪種CSS,JavaScript和DOM節(jié)點(diǎn)。然而,如果你正在采用客戶端檢測(cè),情況則更為復(fù)雜。你有如下幾種選擇:
1. 重定向到特定設(shè)備類型的URL,其中包含該設(shè)備類型的版本。
2. 動(dòng)態(tài)加載設(shè)備特定類型的內(nèi)容。
第一種方法很簡(jiǎn)單,需要采用window.location.href = '/tablet'這種重定向的方式。然而,URL地址會(huì)附加設(shè)備類型的信息,所以你可能想使用HTML5的歷史API來(lái)清理網(wǎng)址。不幸的是,這種方法涉及一個(gè)重定向,所以可能會(huì)很慢,尤其是在移動(dòng)設(shè)備上。
第二種方法實(shí)現(xiàn)更加復(fù)雜。你需要一種機(jī)制來(lái)動(dòng)態(tài)加載CSS和JS,還有(根據(jù)瀏覽器而定)你可能無(wú)法實(shí)現(xiàn)例如自定義<meta viewport> 這樣的事。此外因?yàn)闆](méi)有重定向,你需要在一張頁(yè)面上來(lái)響應(yīng)請(qǐng)求。當(dāng)然,你可以用JavaScript來(lái)實(shí)現(xiàn),但是這可能導(dǎo)致性能緩慢和/或糟糕的代碼,這一切都取決于你的應(yīng)用程序。
選擇客戶端或服務(wù)器方案
下面是在這些方法之間的權(quán)衡:
選擇客戶端 :
基于屏幕尺寸或可擴(kuò)展性的方案和用戶代理比起來(lái)更為長(zhǎng)遠(yuǎn)。
無(wú)需不斷更新用戶代理名單。
選擇服務(wù)器 :
能完全控制什么設(shè)備上加載什么版本。
更好的性能:無(wú)需客戶端重定向或動(dòng)態(tài)加載。
我個(gè)人的偏好是,最開(kāi)始使用device.js和客戶端檢測(cè)。 隨著應(yīng)用的發(fā)展,如果發(fā)現(xiàn)客戶端重定向有明顯的性能問(wèn)題,你可以很容易地刪除device.js腳本,并在服務(wù)器上執(zhí)行用戶代理檢測(cè)。
#p#
DEVICE.JS介紹
device.js是一個(gè)起點(diǎn),這樣做基于語(yǔ)義,依靠媒介查詢進(jìn)行設(shè)備檢測(cè),從而無(wú)需特殊的服務(wù)器端配置,節(jié)省了需要實(shí)現(xiàn)用戶代理字符串解析的時(shí)間和精力。
這個(gè)方法是在<head>標(biāo)簽的頂部用搜索引擎友好的標(biāo)記(linkrel=alternate)聲明你要提供的網(wǎng)站版本。
- <link rel="alternate" href="http://foo.com" id="desktop"
- media="only screen and (touch-enabled: 0)">
接下來(lái),你可以采用服務(wù)器端UA檢測(cè)和版本重定向,或者使用device.js腳本來(lái)執(zhí)行基于功能的客戶端重定向。
更多詳細(xì)信息,請(qǐng)參閱device.js項(xiàng)目頁(yè)面 ,同時(shí)還有一個(gè)使用了device.js進(jìn)行客戶端重定向的測(cè)試應(yīng)用。
建議:MVC的具體視圖
現(xiàn)在你可能會(huì)想,我告訴你的是建立三個(gè)完全獨(dú)立的應(yīng)用程序,每個(gè)用于一種設(shè)備類型。不! 代碼共享是關(guān)鍵。
希望你已經(jīng)使用了一個(gè)類MVC的框架,例如Backbone,Ember等等。如果你已經(jīng)熟悉重點(diǎn)分解的原則,尤其是你的用戶界面(視圖層)應(yīng)該與邏輯(模型層)分離。如果你對(duì)此還比較陌生,可以開(kāi)始了解MVC的一些資源和JavaScript中的MVC 模式。
跨設(shè)備非常適合現(xiàn)有的MVC框架。你可以輕松地移動(dòng)視圖到獨(dú)立的文件,為每個(gè)設(shè)備類型創(chuàng)建一個(gè)自定義視圖。然后你就可以為所有設(shè)備使用除了視圖層之外同樣的代碼。
跨設(shè)備的MVC模式
你的項(xiàng)目可能有以下的結(jié)構(gòu)(當(dāng)然,你可以自由選擇對(duì)你應(yīng)用最有意義的結(jié)構(gòu)):
- 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
這種結(jié)構(gòu)使你能夠完全控制每個(gè)版本加載哪些內(nèi)容,因?yàn)槟惚仨殲槊總€(gè)設(shè)備采用自定義的HTML,CSS和JavaScript。這非常強(qiáng)大,是開(kāi)發(fā)跨端Web App最精簡(jiǎn)和最有效的方式,不會(huì)依賴于一些小的技巧,例如自適應(yīng)圖像。
一旦你運(yùn)行喜歡的構(gòu)建工具,會(huì)把所有的Javascript和CSS合并和壓縮到一個(gè)獨(dú)立的文件里,以實(shí)現(xiàn)更快的加載速度,而輸出的HTML頁(yè)面看起來(lái)類似以下的形式(在手機(jī)上,使用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)媒介查詢并不標(biāo)準(zhǔn)(只有Firefox通過(guò)moz前綴實(shí)現(xiàn)了),但是能夠被device.js正確運(yùn)行(感謝Modernizr.touch)。
版本覆蓋
設(shè)備檢測(cè)有時(shí)候有誤,在某些情況下,用戶可能更喜歡在手機(jī)上采用平板布局(也許他們正在使用Galaxy Note),所以一定要向用戶提供版本的選擇。
通常的做法是提供一個(gè)從桌面到移動(dòng)版本的鏈接。這很容易實(shí)現(xiàn),device.js通過(guò)device的GET參數(shù)來(lái)支持此功能。
結(jié)論
綜上,當(dāng)需要建立跨設(shè)備單頁(yè)的用戶界面時(shí),并不適合響應(yīng)式設(shè)計(jì),我們可以這樣做:
1. 挑選一系列設(shè)備分類進(jìn)行支持,并為設(shè)備分類設(shè)定標(biāo)準(zhǔn)。
2. 建立你的MVC應(yīng)用,把界面從代碼庫(kù)分離出來(lái)。
3. 使用device.js進(jìn)行客戶端設(shè)備分類檢測(cè)。
4. 當(dāng)你準(zhǔn)備好了時(shí),為每個(gè)設(shè)備分類打包你的腳本和樣式表。
5. 如果客戶端重定向有性能問(wèn)題,放棄device.js,并換到服務(wù)器端做UA檢測(cè)。
原文鏈接:http://www.itivy.com/iphone/archive/2012/5/18/634729762320220086.html
【編輯推薦】
【責(zé)任編輯:張偉 TEL:(010)68476606】