移動端適配基礎總結

說到移動端適配,首先咱們須要先搞清楚一些基礎知識,因此本文路線是先了解像素,dpr,視口等基礎知識,而後再整理出移動端適配方案。php

基礎知識

像素

像素其實分爲兩種,分別是物理像素和CSS像素html

  1. 物理像素(設備像素)
    物理像素,顧名思義,顯示屏是由一個個物理像素點組成的,經過控制每一個像素點的顏色,使屏幕顯示出不一樣的圖像,屏幕從工廠出來那天起,它上面的物理像素點就固定不變了,單位pt。
    一般咱們看一些電子設備的參數,好比分辨率用的就是物理像素。它配合屏幕尺寸(注意:屏幕尺寸一般是說屏幕的對角線長度),能夠計算出PPI(每英寸像素取值),即每一英寸物理像素數量。PPI越高,說明屏幕能提供更多細節。
    ppi計算公式
  2. CSS像素
    CSS和js使用的抽象單位,瀏覽器內的一切長度都是以CSS像素爲單位的,CSS像素的單位是px。
  3. 物理像素和CSS像素之間的關係(dppx,DPR)
    在非高清屏及未縮放的狀態下,一個CSS像素等於一個物理像素,而在一些PPI很是高的屏幕(例如蘋果的視網膜屏幕)上,若是還讓一個CSS像素等於一個物理像素,就會致使網頁上的元素變得很是小,所以高PPI屏下,一般一個CSS像素等於兩個甚至三個物理像素(由瀏覽器廠商決定,不一樣瀏覽器設定的值可能不一樣)。若是一個CSS像素佔用n個物理像素,那麼咱們就說此時的dppx(dots per px)爲n。
    因此,咱們能夠用dppx描述物理像素和CSS像素之間的關係。dppx除了和PPI有關,也和當前縮放狀態有關,舉個例子,在非高清屏下,若是沒縮放,一個CSS像素佔用一個物理像素,此時是1dppx,但若是將頁面放大到200%,此時一個CSS像素等於兩個物理像素,即2dppx。
    DPR(設備像素比,devicePixelRatio)描述的是未縮放狀態下,物理像素和CSS像素的初始比例關係,計算方法以下圖。
    DPR計算公式
    DPR由瀏覽器廠商決定,咱們沒法修改,但能夠經過window.devicePixelRatio讀取DPR。
    可能有人疑問DPR和dppx到底啥關係,咱們能夠認爲DPR描述的是未縮放狀態,而dppx能夠描述任意時刻的狀態,未縮放狀態下的dppx和DPR相等,當有縮放操做時,此時的物理像素和CSS像素的比例關係就只能用dppx描述了。

視口(viewport)

視口也叫做初始包含塊,之因此叫這個名字,是由於它包含了元素,它的寬度是全部CSS百分比寬度推算的根源。
在桌面瀏覽器,視口的寬度等同於瀏覽器窗口的寬度,高度即爲瀏覽器窗口的高度。但移動端就有點複雜了,移動端的視口分爲佈局視口和視覺視口。git

  1. 佈局視口(layout viewport)
    說佈局視口以前,咱們先說一下桌面端的頁面放到移動端瀏覽器後出現的問題:因爲早期的頁面不少採用固定寬度的佈局,致使放在移動端的小窗口下出現橫向的滾動條,不便於用戶查看,因此瀏覽器廠商研究出了佈局視口。佈局視口的寬度通常在768px~1024px(由瀏覽器廠商設置),常見寬度980px,雖然設置了很大的寬度,但在沒有手動設置寬度的狀況下,佈局視口仍會容納在一屏裏(說白了,就是把980px的東西裝在320px的屏幕裏),這樣,瀏覽器會避免出現橫向滾動條。
設置佈局視口寬度:<meta name="viewport" content="width=640">
獲取佈局視口寬度:document.documentElement.clientWidth

佈局視口除了和meta設置的width有關,還和scale有關,scale後面會說。github

  1. 視覺視口(visual viewport)
    用戶正在看到的網頁的區域,大小是屏幕中CSS像素的數量。
獲取視口寬度:window.innerWidth/Height

初始狀態下,通常視覺視口會等於佈局視口。web

  1. 理想視口
    當佈局視口的寬度達到理想狀態時,就是理想視口,理想視口中的頁面有最理想的寬度,用戶進入頁面不用縮放。
實現方法:<meta name="viewport" content="width=device-width">(即設置佈局視口寬度爲設備寬度)

縮放(scale)

原理:能夠理解爲修改dppx,舉個例子,假設一屏幕DPR爲2,即1px對應2pt,若是這個時候,咱們設置scale=0.5,那麼dppx就會從2變成1,即1px對應1pt。因此,經過縮放咱們能夠調整本身所能控制的最小物理像素粒度。
縮放會影響佈局視口的大小,由於瀏覽器會盡可能讓佈局視口鋪滿屏幕,因此當咱們設置scale=0.5時,佈局視口的寬度會自動變爲原來的兩倍。
具體以下圖所示。
選擇的移動調試設備瀏覽器

<meta name="viewport" content="width=device-width,initial-scale=1.0">
    <script>
        console.log(document.documentElement.clientWidth);   //結果爲375
    </script>
<meta name="viewport" content="width=device-width,initial-scale=0.5">
    <script>
        console.log(document.documentElement.clientWidth);   //結果爲750
    </script>

可能有人會問,scale的初始值是多少?其實這取決於viewport的寬度,由於瀏覽器會盡可能讓佈局視口鋪滿全屏,因此瀏覽器會根據佈局視口的大小動態調整scale的初始值大小,從而使佈局視口鋪滿全屏。
使用縮放的好處:對於DPR爲2或更高的屏幕,若是不作縮放操做,咱們所能控制的最小物理像素粒度是2pt或更多物理像素,這樣帶來了兩個問題。wordpress

  • 若是設計圖上某個邊框標識的大小是1px,那說明設計師想讓這個邊框在任何屏幕上都是1像素,在普通屏幕上,不會有問題,但在retina這種高清屏上,當咱們用1px修飾border時,實際上會有2pt渲染爲border,致使border看上去比普通屏的border寬。
<style>
#log {
    border: 1px solid black;
}
</style>
<div id="log"></div>

scale=0.5

scale=1.0

  • 對於高清屏,若是咱們控制像素的粒度仍是2pt或3pt,實際上咱們並無充分利用高清屏展示細節的能力。

解決這兩個問題的方法就是縮放,咱們把scale設置爲1/dpr。佈局

meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no');

這樣1px就對應1pt,咱們就能夠解決1px border問題和圖片的高清問題了。flex

適配方案

  1. 固定高度,寬度自適應
    即垂直方向使用固定大小,水平方向使用百分比,flex。
<meta name="viewport" content="width=device-width,initial-scale=1">

適合場景:比較適合列表式的結構。優化

  1. 固定寬度,viewport縮放
    開發頁面時徹底按照和設計圖1:1的比例開發,設計圖,頁面,視口寬度使用同一個寬度,單位使用px便可,因爲瀏覽器會盡可能將佈局視口鋪滿全屏,因此瀏覽器會自動幫助咱們縮放。舉個例子,假設設計圖是640px寬,那咱們這樣設置。
<meta name="viewport" content="width=640">

這個時候會發現,瀏覽器會幫助咱們將頁面鋪滿全屏,並且這是絕對的等比例縮放。圖片、文字等等全部元素都被縮放在手機屏幕中。

  1. rem作寬度,viewport縮放
    根據屏幕寬度設定rem值,須要適配的元素都使用rem爲單位,不須要適配的元素仍是使用 px 爲單位。
    總共分兩步:

    • 動態設置font-size
    document.getElementsByTagName('html')[0].style.fontSize = window.innerWidth / 10 + 'px';
    • 縮放viewport
    meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no');

第二步是對頁面適配的優化,修改scale是爲了解決前面說到的1px border問題。
淘寶的Flexible使用的就是這種方案,並且它加了data-dpr屬性,這樣咱們就能夠根據不一樣的DPR設置不一樣的樣式。

方案總結

方案一比較適合列表這種比較固定的結構,方案二適合的場景比較多,並且實現簡單,但須要注意它會將頁面的全部元素都縮放,方案三適合的場景是頁面內有些元素須要適配,有些元素不須要適配。整體來說,方案二和方案三是比較經常使用的方式。

參考文獻:

https://www.zybuluo.com/gongzhen/note/170557
鄭航的知乎回答https://www.zhihu.com/question/35221839
https://github.com/amfe/article/issues/17
https://github.com/riskers/blog/issues/18
https://riskers.github.io/share/share/flexible.htm#1
https://github.com/riskers/blog/issues/17
https://github.com/amfe/lib-flexible
http://www.html-js.com/article/2402
http://www.alloyteam.com/2016/03/mobile-web-adaptation-tool-rem/
https://www.nihaoshijie.com.cn/index.php/archives/593
http://www.zhangxinxu.com/wordpress/2012/08/window-devicepixelratio/

相關文章
相關標籤/搜索