也談多終端屏幕適配

寫在前面

在移動網民規模不斷擴大的今天,手機、平板等移動設備儼然已成了網民主要上網終端。迎着這個勢頭,咱們這些前端汪們也接下了很多的移動web頁面開發需求。當在感嘆終於不須要兼容pc端低端瀏覽器時卻面臨了移動多終端屏幕適配這一問題。css

本人經驗尚淺,在大牛們得出的數種適配方案的基礎上也來談談這一問題。 //實際上是入職前太頹廢了,找點事作html

因爲本文目的不在於普及基礎,因此移動端相關概念(viewportcss像素,獨立像素,物理像素,dprdpippi)的闡明再也不贅述。前端

能夠參考:android

還沒有有時間研究原理的同行們,能夠跳過這些直接看下面的解決方案。github

這裏是以前記錄的以 iPhone 6 例子的一個總結:web

clipboard.png

何爲多終端適配?viewport 有多重要?

多終端適配即便某一套網頁方案能完美地展現在不一樣操做系統、尺寸、分辨率、dpr的設備上。適配的緣由相比也不用多說了——就是爲了使網站各終端的用戶都不流失。瀏覽器

來看看瀏覽器產商爲咱們提供的最原始的解決方案。app

在iphone誕生前,爲了留住移動端用戶,手機瀏覽器嘗試經過調整內容來適應網頁,取得了不一樣程度的成功。

iphone上的safari沒有作絲毫的嘗試,取而代之的是在各類各樣的虛擬窗口上展現網頁,這些虛擬窗口被稱爲「視圖」。用戶能夠經過放大來查看網頁的部份內容或縮小來查看網頁的所有內容。爲了給開發者提供必定程度的展示頁面的控制權,蘋果公司提供了viewportmeta元素,它能夠指定虛擬窗口的大小。
——《HTML5觸摸界面設計與開發》

iphone的viewport(視口)默認大小爲980px。意味着會使得在pc端顯示爲980px的網頁以必定比例縮小(瀏覽器會替咱們完成這一工做)成剛好能夠容納在4.7英寸(以iphone6爲例)屏幕內。這樣一來,整個網頁縮小得咱們不容易直接觀測到裏面的信息,必須經過手勢放大頁面獲取。

如圖,這個頁面我沒設置viewport,設計稿基於iphone6,因此頁面內容寬度定爲750px。很明顯看出左右兩旁的空白,即寬度爲達到視口寬980px所產生的。

clipboard.png

so——構建移動頁面時,設置合理的viewport值是首要任務。

那麼什麼是合理的viewport值呢?其實每一個瀏覽器的viewport都不盡相同:

  • Safari iPhone:980px

  • Opera:850px

  • Android WebKit:800px

  • IE:974px

面對衆多的默認viewport,使其統一爲一個值是業界的廣泛作法。常見的設置有:

<meta name="viewport" content="target-densitydpi=device-dpi,width=設計稿尺寸,initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no" />
<meta name="viewport" content="target-densitydpi=device-dpi,width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />

因此通常來講,viewport的寬度會設定爲device-width(設備寬度,與css邏輯像素同等大小,可經過document.documentElement.clientWidth獲取)或者爲設計稿尺寸(好比設計稿基於iphone6,width=750;基於ip5,width=640)。

這裏須要注意:initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5 這幾個縮放數值一般是經過ua檢測,再經過js自動設置的。通常不會固定爲1或者某一特定數值。但也有特殊狀況。稍後討論。

解決方案

前提

設計師給出的視覺稿應該嚴格按照某一移動設備的屏幕物理像素制定寬度,高度視頁面內容而定。業界通常是基於iphone5或者6給出相應尺寸。因此最多見的視覺稿有750px、640px的。而1080px的大可能是基於6plus的。而其餘的奇葩尺寸真心不建議了。因此應事先約定好。

對於多倍圖處理能夠看看 @南宮瑞揚 翻譯的這張圖:

clipboard.png

1、自適應適配方案

一、使用場景

佈局簡單,主要內容以列表形式展現:條目內容垂直分佈。定位元素少,且不爲主要內容元素。如知乎美團網微博通常結構爲:

  • 頂欄:搜索框或網站logo等信息

  • banner

  • 橫向導航:通常爲若干個平分水平空間的tap

  • 內容:含有標題和描述或還包含略所圖

二、解決方案

a.設置viewport:

<meta name="viewport" content="target-densitydpi=device-dpi,width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />;

b.水平方向寬度自適應,垂直方向高度固定

若元素無其餘平分空間的兄弟元素,寬度可定爲設計稿元素寬度/設計稿寬度*100%;如有寬度定爲100%/平分空間元素個數,也能夠用flex的方式定義;

c.小塊的元素(如logo,裝飾性圖片)寬高都固定;

d.注意圖片在retina屏幕下應使用多倍圖,但仍以1倍圖的大小肯定圖片的寬高。如果sprite圖,可設background-size: x1圖片寬 auto;background-position: 以x1 sprite圖片定義

三、弊端

元素高度和圖片大小以同一個尺寸在多種不一樣尺寸的設備下顯示,沒達到真正適配效果。沒法適應結構複雜的頁面佈局。

2、固定viewport爲設計稿大小

一、使用場景

頁面只考慮移動設備,不考慮自適應,不須要作響應式佈局。非h5專題活動頁。如網易新聞、我以前作過的一個團購網站cocolife也用的是這種方式

二、解決方案

a.設置viewport

<meta name="viewport" content="target-densitydpi=device-dpi,width=設計稿寬度,user-scalable=no" />

或經過js寫入meta

var scale= parseInt(window.screen.width)/設計稿寬度;
document.write('<meta name="viewport" content="width=設計稿寬度, initial-scale = '+scale+', maximum-scale = '+scale+', maximum-scale = '+scale+', target-densitydpi=device-dpi">');
}

注意這裏的設計稿是指初始的設計稿大小。通常以iphone6:750px;iphone5:640px定寬。

b.頁面全部元素的寬高都按設計稿元素自己大小直接定義。

三、弊端

乍眼看上去這種方法挺好的,所有按設計稿給出的元素大小寫成固定px值,不須要各類單位轉換。所看即所得,縮放交給瀏覽器,徹底按視覺稿切圖。但,爲何沒有獲得普片推廣呢?

第一點是再也不支持響應式佈局。好比咱們定義的`@media
(min-width:320px)`這裏的width實際上指的是viewport的寬度值,而咱們的viewport已經固定成統一寬度了(如640px),因此,不管在哪一個尺寸的屏幕下,這句媒體查詢也再也不起做用了。
第二點是這種方式會讓瀏覽器去縮放,那麼就可能會形成字體模糊,圖像失真。1px border在 不一樣分辨率下的顯示也會有所不一樣。
第三點是若是頁面要嵌入到App中時,App是以webview的形式渲染頁面的。webview實際上也是webkit內核,而最新的webkit內核對定寬支持不是很好,默認是以device-width來渲染的。
第四點是可能存在縮放失效的問題,某些安卓機不能正常的根據 meta 標籤中 width 的值來縮放 viewport,須要配合 initial-scale(即上述js方式) 。

3、淘寶的作法

一、使用場景

廣泛網站均可以採用這種方式。但不包括h5專題活動頁。

二、解決方案

這裏首先推薦大漠前輩的一篇文章使用Flexible實現手淘H5頁面的終端適配

淘寶作法的原理相信你們可能比較熟悉。簡單地說就是動態設置html下的font-size值,而後爲頁面的元素採用rem的方式制定寬高。

咱們知道rem的佔據像素值是由根元素的font-size值大小決定的。打個比方,若html下設置了font-size:16px;那麼1rem就至關於16px

淘寶的方案大體以下:

clipboard.png

把頁面分紅10等份,若視覺稿初始寬度爲750px,那麼每份大小爲75px,將值給予font-size,那麼1rem=75px。加上初始的縮放值

clipboard.png

使得寬度爲10rem的盒子正好容納在iphone6視口(375px)上。若此時視口的大小變成320px,那麼js就會將htmlfont-size值動態改變爲64px

來看看js是怎麼動態改變font-size

//UA檢測
var isAndroid = win.navigator.appVersion.match(/android/gi),
    isIPhone = win.navigator.appVersion.match(/iphone/gi);

//對ios設備的dpr進行判斷,安卓統一設定爲1
var dpr= isIPhone ? Math.min(win.devicePixelRatio, 3) : 1;
    scale = 1 / dpr;
    
var docEl = document.documentElement;
var metaEl = doc.createElement('meta');

//設定dpr和meta
docEl.dataset.dpr = dpr;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
docEl.documentElement.firstElementChild.appendChild(metaEl);

//動態設定根元素下的font-size大小
var width = docEl.getBoundingClientRect().width;
//pc等大屏幕下
if (width / dpr > 540) {
     width = 540 * dpr;
}
//將頁面分爲10等份,易得出750px視覺稿下根元素font-size爲75px
var rem = width / 10;
docEl.style.fontSize = rem + 'px';

上面的js粗略地描述了一下淘寶的方案。即將font-size值設置成docWidth(視覺稿大小)/10,那麼1rem大小同爲docWidth/10。因此頁面裏的元素寬高爲width/(docWidth/10)

舉個栗子:

若咱們拿到一個基於iphone6的視覺稿,對其運用該種方式進行適配。因爲iphone6視覺稿寬度爲750px,那麼只須要將視覺稿上的元素大小初始寬高/75寫入css。

如寬度爲750pxwrap,則width=10rem;寬度爲375pxarticle,則width=5rem
scss$ppr(pixel per rem) 變量寫法:$ppr: 750px/10/1rem
元素尺寸寫法:html { font-size: $ppr*1rem; } body { width: 750px/$ppr; }

4、專題活動 h5

一、使用場景

針對專題活動的滑屏h5頁面,特色是主題內容圖片居多,而且基本採用絕對定位方式。

二、解決方案

原理:給每屏下的主要內容加一個container包裹元素,並設置margin: 0 auto使其水平居中。(保證內容在視線中央)使用jscontainer總體進行transform:scale()縮放,scale值根據屏幕窗口大小動態設置。

2.1 推薦一個框架以快速搭建適配的h5:pageResponsive

2.2 不使用框架的具體作法:

a.設定viewport

<meta name="viewport" content="target-densitydpi=device-dpi,width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />;

b.頁面結構

通常爲

<ul>
    /*---第一屏---*/
    <li><div class="container"><div><li>
    /*---第二屏---*/
    <li><div class="container"><div><li>
    /*---第三屏---*/
    <li><div class="container"><div><li>
    ...
<ul>

通常來講h5有contain和cover兩種適配模式。

contain即將頁面固定在一個特定大小的盒子中。背景通常以與h5背景顏色相近的純色替代。像這樣:

clipboard.png

cover即將h5每一屏的背景或者從緊貼邊緣的圖像經過調整background-size使之剛好容納在窗口中。像這樣:

clipboard.png

下面說說兩種模式的h5寫法(默認遵循上述的html結構):

contain:

對於每一屏下背景或者從邊緣開始顯示的大圖定義在li下,採用background-size:100% 圖像高度的方式。

cover:

把全部元素放置在.container下統一進行縮放。背景定義在.container下。同時給.container設置固定的寬高,通常320*520的居多。

c.進行動態縮放的js

// 響應式縮放
var autoScale = function() {
var ratio = 320/508,
    winW = document.documentElement.clientWidth,
    winH = document.documentElement.clientHeight,
    ratio2 = winW/winH,
    scale;
//判斷寬和高以哪一個爲縮放基準    
if (ratio < ratio2) {
        scale = (winH/508).toString().substring(0, 6);
    } else {
        scale = (winW/320).toString().substring(0, 6);
    }
var cssText = '-webkit-transform: scale('+ scale +'); -webkit-transform-origin:top center; opacity:1;';
$(".container").attr('style', cssText);

};

//這裏使用setTimeout是因爲獲取文檔寬高時有時候不能馬上獲得,形成縮放失效
setTimeout(function() {
    if (document.documentElement.clientWidth/document.documentElement.clientHeight !== 320/508) {
        autoScale();
    } else {
        $('.container').css({'opacity': 1});
    }
}, 300);

總結

經過上述分析,得出如下總結供你們對適配方案進行選擇。

拿到視覺稿
      ↓
判斷佈局是哪一種類型
      ↓
1.內容少,絕對定位圖片少,佈局簡單,通常爲上下結構
      ↓
是否須要適配PC?
是 → 自適應方式  
否 → 自適應、rem、viewport方式
      ↓
是否要嵌入APP或運用響應式佈局?
是 → 自適應、rem方式
否 → 自適應、rem、viewport方式  //推薦使用自適應方式

2.內容適中,絕對定位元素少
      ↓
是否要嵌入APP或運用響應式佈局?
      ↓
是 → rem方式
否 → rem方式或viewport方式  //推薦使用rem方式

3.整屏專題H5;絕對定位元素多  
      ↓
是否須要適配PC?
      ↓
是 → H5專題頁面的cover方式
否 → H5專題頁面的contain方式

^^感謝閱讀!

相關文章
相關標籤/搜索