移動Web開發之移動頁面佈局 ========================================== 前言 本文針對手機設備設計的頁面,並非相容全設備的響應式佈局,常見的MobileWeb頁面如H5頁面、手機頁面、WAP頁、webview頁面等等。在不同尺寸的手機設備上,頁面 “相對性 ...
移動Web開發之移動頁面佈局
前言
本文針對手機設備設計的頁面,並非相容全設備的響應式佈局,常見的MobileWeb頁面如H5頁面、手機頁面、WAP頁、webview頁面等等。在不同尺寸的手機設備上,頁面“相對性的達到合理的展示(自適應)”或者“保持統一效果的等比縮放(看起來差不多)。
深入概念引出viewport
Pixel
- 設備像素
- 在LCD顯示器中,基於點陣排列,每一個像素右由紅綠藍子像素組成
CRT顯示器
- CSS像素(用於控制元素樣式的樣式單位像素,是一個相對值)
CSS像素與屏幕像素1:1同樣大小時:
瀏覽器視窗寬度一定的情況下,把頁面放大(Ctrl+),CSS像素(黑色邊框)開始被拉伸,此時1個CSS像素大於1個屏幕像素
ppi(Pixel Per Inch)
- 這裡討論的是只針對顯示設備(另外還有列印照片時的解析度、列印精度),指的是屏幕密度。PPI全稱為Pixel Per Inch,譯為每英寸像素取值。ppi值越高,單位面積內所占的像素越多,顯示的畫質越好。
PPi中的pixel指的是物理(設備)像素。
ppi是每台設備的一個定值,一個固定參數,下圖以Samsung Galaxy S4為例
ppi過高帶來的問題,相同的圖片素材,ppi越高的設備顯示越小。下圖為一個解析度像素在屏幕中的位置
由於這樣的問題存在,高ppi(高清屏)設備下的UI會採取一定的縮放比例,讓文本或素材放大(也就是讓解析度像素或CSS像素放大),下麵是CSS像素和物理像素的比例公式:DevicePixelRatio是手機的物理像素與實際使用像素的縮放比(會隨著手機預設縮放比和人為縮放瀏覽器頁面改變))
DevicePixelRatio定義如下: window.devicePixelRatio = physical pixels / dips(device-independent pixels即CSS像素)
dppx(dots per pixel)
- 表示單個CSS像素占用的物理像素個數,與DPR等價,只不過是從微觀的角度。
dpi(Dots per inch)
- 對於顯示設備的像素密度而言,dpi與ppi是等價的。
CSS Reference Pixel
- W3C規定(CSS Reference Pixel),把人眼能夠辨別到的,距離自己一個手臂長度(約28英寸),像素密度為96dpi設備上的一個物理像素設為參考像素(目的是為了保證CSS像素在不同設備、不同距離觀測到的大小一致)
通過CSS參考像素可以計算出在不同的設備上使用合適的CSS像素大小,使得視覺上一致。
那麼問題來了,如何實踐這個標準呢?通過使用viewport
<meta name="viewport">
viewport
預設情況下,手機屏幕以980px去渲染頁面,(下圖圖像為320px,設備為iphone4)
此時通過設置渲染寬度為320px,即為手機設備的解析度,此時圖像是充滿整個區域的
- 通過上面可得,可以設置width=device-width(手機屏幕解析度),指定佈局寬度等於手機解析度寬度,可以實現
- 為移動設備開發的響應式網頁時,你會面臨多重解析度情況,沒有必要使用到重量級的mediaquery
- 避免手機瀏覽器使用桌面解析度寬度(980px等)去渲染頁面
- 相容手機橫屏或豎屏
下麵為viewport的一般設置
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
另外Viewport還分為兩種,Layout Viewport和Visual Viewport
還原視覺稿,多屏適配
- 對於移動端開發而言,為了做到頁面高清的效果,視覺稿的規範往往會遵循以下兩點:
- 首先,選取一款手機的屏幕寬高作為基準(以前是iphone4的320×480,現在更多的是iphone6的375×667)。
- 對於retina屏幕(如: dpr=2),為了達到高清效果,視覺稿的畫布大小會是基準的2倍,也就是說像素點個數是原來的4倍(對iphone6而言:原先的375×667,就會變成750×1334)。]
- 字體、高寬間距、圖像(圖標、圖片)
- 矢量化、字體化、image-set等
- 在滿足快速開發的需求下,利用 css 將圖像限定在元素內( img 圖片使用
[max-]width: 100%
,背景圖像使用background-size
),佈局只針對元素進行。
- 幾個問題(詳情)
- retina下,圖片高清問題
- retina下,border: 1px問題
- 多屏適配佈局問題
- 字體大小問題
以下圖為例,分析移動Web開發在頁面架構和佈局的方法及差異性(效果圖為640px)
1.固定高度,寬度自適應
- 實現
- viewport width 設置為
device-width
,以較小寬度(如 320px)的視覺稿作為參照進行佈局 - 垂直方向的高度和間距使用定值,水平方向混合使用定值和百分比或者利用flex彈性佈局
- 圖像元素根據容器使用定值或background-size縮放
代碼段
<meta name="viewport" content="width=device-width,initial-scale=1">
- viewport width 設置為
- 要點
- 由於高度固定,寬度自適應,在大屏幕手機下元素被拉長了,所以設計的時候只能設計橫向拉伸的元素佈局,存在很多局限性。
- 以小寬度作為參照是因為如果佈局滿足了小寬度的擺放,當屏幕變寬時,簡單的填充空白就可以了(比如網易新聞);而如果反過來就可能造成“擠壞了”,考慮 header 區域,左測 logo 右測橫向 nav 的情況。
- 需要小寬度的佈局,又需要大寬度的圖像,這是一個矛盾點。
- 相容性較好。
- 案例
2.固定寬度,viewport縮放
- 實現
- 視覺稿、頁面寬度、viewport width 使用統一寬度,利用瀏覽器自身縮放完成適配。頁面樣式(包括圖像元素)完全按照視覺稿的尺寸,使用單位
px
即可。 - 固定寬度值考慮以下兩點:
- 主流解析度,參考Screen Sizes和友盟指數的數據
- 設計部門常用尺寸
- 代碼段
head頭部(根據屏幕寬度來動態生成viewport,生成的 viewport 基本是這樣)
<meta name="viewport" content="width=640,initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">
css style
body { width: 640px; margin: 0 auto; }
- 視覺稿、頁面寬度、viewport width 使用統一寬度,利用瀏覽器自身縮放完成適配。頁面樣式(包括圖像元素)完全按照視覺稿的尺寸,使用單位
- 優點:
- 開發簡單:縮放交給瀏覽器,完全按視覺稿切圖。
- 還原精準:絕對等比例縮放,可以精準還原視覺稿(不考慮清晰度的情況下)。
- 測試方便:在PC端即可完成大部分測試,手機端只需酌情調整一些細節(比如圖標、字體混合排列時,因為字體不同造成的對齊問題)。
- 存在的問題:
- 像素丟失:對於一些解析度較低的手機,可能設備像素還未達到指定的 viewport 寬度,此時屏幕的渲染可能就不准確了。比較常見的是邊框“消失”了,不過隨著手機硬體的更新,這個問題會越來越少的。
- 縮放失效:某些安卓機不能正常的根據 meta 標簽中 width 的值來縮放 viewport,需要配合 initial-scale 。
- 文本折行:存在於縮放失效的機型中,某些手機為了便於文本的閱讀,在文本到達 viewport 邊緣(非元素容器的邊緣)時即進行折行,而當 viewport 寬度被修正後,瀏覽器並沒有正確的重繪,所以就發現文本沒有占滿整行。一些常用的段落性文本標簽會存在該問題。
- 解決問題
縮放失效問題需通過 js 動態設定 initial-scale。
var fixScreen = function() { var metaEl = doc.querySelector('meta[name="viewport"]'), metaCtt = metaEl ? metaEl.content : '', matchScale = metaCtt.match(/initial\-scale=([\d\.]+)/), matchWidth = metaCtt.match(/width=([^,\s]+)/); if ( metaEl && !matchScale && ( matchWidth && matchWidth[1] != 'device-width') ) { var width = parseInt(matchWidth[1]), iw = win.innerWidth || width, ow = win.outerWidth || iw, sw = win.screen.width || iw, saw = win.screen.availWidth || iw, ih = win.innerHeight || width, oh = win.outerHeight || ih, ish = win.screen.height || ih, sah = win.screen.availHeight || ih, w = Math.min(iw,ow,sw,saw,ih,oh,ish,sah), scale = w / width; if ( ratio < 1) { metaEl.content += ',initial-scale=' + ratio + ',maximum-scale=' + ratio + ', minimum-scale=' + scale; } } }
文本折行問題
section, p, div, h1, h2, h3, h4, h5, h6, .fix-break { background: tranparent url('about:blank'); word-break: break-all; }
- 案例
3.rem做寬度,viewport縮放
- 實現
- 依照某特定寬度設定 rem 值(即 html 的 font-size),頁面任何需要彈性適配的元素,尺寸均換算為 rem 進行佈局,不需要適配的元素還是使用
px
為單位。 - 當頁面渲染時,根據頁面有效寬度進行計算,調整 rem 的大小,動態縮放以達到適配的效果。
- 根據 devicePixelRatio 設定 initial-scale 來放大 viewport,使頁面按照物理像素渲染,提升清晰度。
- 通過JS去動態計算根元素的font-size(所有設備均相容),也可以使用media query(相容自己網站主流的一些屏幕設備)
- 根據設備像素比(window.devicePixelRatio)給設置data-dpr
代碼段(動態生成 viewport)
不用寫 meta 標簽,該方法mobile-util.js根據 dpr 自動生成,併在 html 標簽中加上 data-dpr 和 font-size 兩個屬性值。
- 依照某特定寬度設定 rem 值(即 html 的 font-size),頁面任何需要彈性適配的元素,尺寸均換算為 rem 進行佈局,不需要適配的元素還是使用
- 優點:
- 清晰度高,能達到物理像素的清晰度。
- 能解決 DPR 引起的“1像素”問題。
- 向後相容較好,即便屏幕寬度增加、PPI 增加該方案依舊適用。
- 缺點:
- 適配 js 需儘可能早進入,減少(避免)viewport 變化引起的重繪。
- 某些Android機會丟掉 rem 小數部分。
- 需要預編譯庫進行單位轉換。
一些註意的地方
- chrome當font-size小於12時,rem會按照12來計算,設置基準值要考慮這一點。
- 較小的背景圖(比如一些 icon)的 background-size 不要使用具體 rem 數值,裁剪後會出現邊緣丟失。應使用與元素等尺寸切圖,設定
background-size: contain|cover
來縮放。
動態調整 rem 的方法如下:
var fixScreen = function() { var metaEl = doc.querySelector('meta[name="viewport"]'), metaCtt = metaEl ? metaEl.content : '', matchScale = metaCtt.match(/initial\-scale=([\d\.]+)/), matchWidth = metaCtt.match(/width=([^,\s]+)/); if ( !metaEl ) { // REM var docEl = doc.documentElement, maxwidth = docEl.dataset.mw || 750, // 每 dpr 最大頁面寬度 dpr = isIos ? Math.min(win.devicePixelRatio, 3) : 1, scale = 1 / dpr, tid; docEl.removeAttribute('data-mw'); docEl.dataset.dpr = dpr; metaEl = doc.createElement('meta'); metaEl.name = 'viewport'; metaEl.content = 'initial-scale=' + ratio + ',maximum-scale=' + ratio + ', minimum-scale=' + scale; docEl.firstElementChild.appendChild(metaEl); var refreshRem = function() { var width = docEl.getBoundingClientRect().width; if (width / dpr > maxwidth) { width = maxwidth * dpr; } var rem = width / 16; docEl.style.fontSize = rem + 'px'; }; //... refreshRem(); } }
- 案例
4.響應式佈局(pc & mobile)
- 實現
- 使用 viewport meta 標簽在手機瀏覽器上控制佈局
- 使用 Media Queries 適配對應樣式
- 要點
- 響應式這種方式在國內很少有大型企業的複雜性的網站在移動端用這種方法去做,主要原因是工作大,維護性難
- 適用於中小型的門戶或者博客類站點會採用響應式的方法從web page到web app直接一步到位,因為這樣反而可以節約成本,不用再專門為自己的網站做一個web app的版本。
- 優點
- Native APP:Objective-C or Java – 學習成本高
- Hybrid APP: 外殼+Web APP,需安裝。
- 響應式Web APP:HTML5+JS+CSS – 門檻低,極易上手,迭代快
無需安裝成本,迭代更新容易
- 案例
小結
- 前三種方案為H5頁面、手機頁面、WAP頁、webview頁面
移動
常用方案 - 第一種方案只能做一些列表等簡單排列的樣式,面對更複雜的頁面,往往需要絕對定位和百分比等,尺寸與視覺稿有出入。
- 第二種和第三種方案不會和設計圖有差,第三種方案比第二種方案更靈活,有兩種單位可用,
rem
和px
。 - 靈活運用min-height和min-width
- 能用flex佈局的不要使用浮動和絕對定位(不利於頁面擴展)
移動開發規範
字體設置
- 使用無襯線字體
- iOS 4.0+ 使用英文字體 Helvetica Neue,之前的iOS版本降級使用 Helvetica。中文字體設置為華文黑體STHeiTi。 需補充說明,華文黑體並不存在iOS的字體庫中http://support.apple.com/kb/HT5878, 但系統會自動將華文黑體 STHeiTi 相容命中系統預設中文字體黑體-簡或黑體-繁
原生Android下中文字體與英文字體都選擇預設的無襯線字體
body { font-family: "Helvetica Neue", Helvetica, STHeiTi, sans-serif; }
基礎交互
設置全局的CSS樣式,避免圖中的長按彈出菜單與選中文本的行為
a, img { -webkit-touch-callout: none; /* 禁止長按鏈接與圖片彈出菜單 */ } html, body { -webkit-user-select: none; /* 禁止選中文本(如無文本選中需求,此為必選項) */ user-select: none; }
跨瀏覽器測試
瀏覽器相容性:
- pc端模擬
- PC端Chrome瀏覽器模擬手機調試頁面,佈局上幾乎和真機上沒有差別了,只是真機可以看到的細節更多、操作真實環境
- 真機調試
- 微信、手機QQ、QQ瀏覽器:可以使用騰訊TBS studio、手機、usb數據線可以在測試線上頁面
- Android:通過手機chrome、PC chrome和usb;連接數據同樣可以在手機上chrome瀏覽器對頁面進行調試。
- 更多更詳細測試方案
實踐應用
- demo1(運用的是第一種方案,但是有些元素高度沒有固定,而是自適應,以此適應圖片的縮放。)
參考資料
- web app變革之rem
- 手機淘寶的flexible設計與實現
- MobileWeb 適配總結
- 移動端高清、多屏適配方案
- 淺談移動Web開發
- 響應式網頁設計
- 移動端適配方案(下)
- Alloyteam移動開發規範概述
拓展閱讀
- mobileTech
- CSS 與 JS 註意事項
- 關於webapp中的文字單位的一些搗騰
- 移動前端開發和 Web 前端開發的區別是什麼
- MDN:手機網頁開發
- MDN:在移動瀏覽器中使用viewport元標簽控制佈局
- 手機/移動前端開發需要註意的20個要點
- w3cplus響應式技術資源
- Alloyteam Mars
- 移動WEB開發入門
- 移動開發資源集合
- The Mobile Web Handbook
- 移動前端不得不瞭解的html5 head 頭標簽