移動web必會技能--屏幕適配(物理像素CSS像素)

屏幕適配,一直是做爲一個前端開發始終逃不掉的問題,這個話題能夠追溯到最開始的PC端瀏覽器的不一樣分辨率,再到移動端不一樣的屏幕尺寸,一直伴隨着前端工程師的平常的頁面開發工做。所謂屏幕適配,能夠理解爲一個網頁元素或者網頁佈局,在不一樣尺寸,分辨率等場景下,如何呈現最佳的效果。 從最先的PC端屏幕來講,大部分的屏幕適配採起的是:javascript

  • 頁面框架最外層元素寬度固定,而且居中,高度隨內容自適應,比較常見的是寬度爲960px~1080px。
  • 頁面內部的元素大多數使用盒子模型構建,採用固定寬高,當內容超出時,會出現滾動條。
  • 對於一些須要根據屏幕不一樣而展現不一樣大小的元素,能夠給元素設置百分比的單位。

隨着HTML5和CSS3的到來,逐漸出現了彈性佈局(flex佈局),媒體查詢Media Query,和響應式頁面概念,這些特性均可以應用在PC端以及移動端屏幕適配解決方案中。除了這些以外,還有rem和vw方案更加有針對性的解決移動web頁面的適配問題。css

Viewport視窗

在HTML代碼的<head>標籤中,都有一行設置的代碼,以下:html

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
複製代碼

這行代碼的做用就是設置瀏覽器的視窗大小,具體的含義咱們後面在介紹,在講解視窗以前,咱們首先須要瞭解一下什麼是物理像素和CSS像素。前端

物理像素和CSS像素

像素,也就是px,實際是pixel的縮寫,它是圖像顯示的基本單元,每一個像素能夠有色彩數值和位置,每一個圖像是由若干個像素組成,好比對一幅標有1024×768像素的圖像,就代表這幅圖像的長邊有1024個像素,寬邊有768個像素,共有1024×768=786432個像素組成。可是從概念上來講,像素既不是一個肯定的物理量,也不是一個點或者小方塊,而是一個抽象概念。因此像素所表明的具體含義要從其處於的上下文環境來具體分析。物理像素和CSS像素就是不一樣的上下文。java

  • 物理像素:設備屏幕實際擁有的像素點,主要和渲染硬件相關。好比iPhone6的屏幕在寬邊有750個像素點,長邊有1334個像素點,因此iPhone6總共有750*1334個物理像素。
  • CSS像素:也叫邏輯像素,是軟件程序系統中使用的像素,每種程序能夠有本身的邏輯像素,在web前端頁面就是對應的CSS像素,邏輯像素在最終渲染到屏幕上時由相關係統轉換爲物理像素。
  • 設備像素比:一個設備的物理像素與邏輯像素之比。能夠在JavaScript中使用window.devicePixelRatio獲取到。

其實對於早期PC端web頁面來講,在的CSS裏寫個1px,屏幕就給你渲染成1個實際的像素點,此時的設備像素比是1,這時物理像素和CSS像素是同樣的。可是對於一些高清屏,例如蘋果的retina屏幕,這種屏幕使用2個或者3個物理像素來渲染1個CSS像素,因此這些屏幕的顯示效果要清晰不少。例以下圖a表明物理像素,b表明CSS像素,它們之間的關係如圖下圖所示。 web

圖片描述
能夠想象一下,一個傳統的PC端web頁面,若是想要徹底放在手機端使用瀏覽(能夠想象成把PC端顯示器替換成手機屏幕),必定是放不下的,而這時就須要對頁面進行縮放,那麼對頁面進行放大和縮小,其實就是改變像素比,例以下圖,用4個CSS像素和4個物理像素來模擬放大和縮小。
圖片描述
在頁面處於正常狀態時,4個物理像素的區域須要4個CSS像素恰好展現完,當頁面縮小時,本來4個物理像素須要大於4個CSS像素才能顯示完這片區域,而當頁面放大時,本來4個物理像素須要小於4個CSS像素就能夠顯示完,或者說是4個CSS像素可以放下更多於4個物理像素的位置。這就實現了頁面的放大和縮小,而對於HTML而言,控制放大和縮小的就是視窗Viewport。

視窗

在瞭解了物理像素和CSS像素的概念以後,而後就須要引入下一個概念,移動設備中的視窗,視窗就是瀏覽器顯示頁面內容的屏幕區域,有3種不一樣的類別,主要分爲:前端工程化

  • 物理視窗(Visual Viewport):表示物理屏幕的可視區域,屏幕顯示器的物理像素,也就是長寬邊上有多少個像素點。一樣尺寸的屏幕,像素點越多,像素密度越大,它的硬件像素會更多。能夠理解成物理視窗的大小就是屏幕的大小。
  • 佈局視窗(Layout Viewport):是由瀏覽器廠商提出的一種虛擬的佈局視窗,用來解決頁面在手機上顯示的問題。這種視窗能夠經過<meta>標籤設置viewport來修改。每一個瀏覽器默認都會有一個設置,例如iOS,Android這些機型設置佈局視窗寬度爲980px,因此PC上的網頁基本能在手機上呈現,只不過元素看上去很小,通常能夠經過手指動雙擊縮放網頁。
  • 理想視窗(Ideal Viewport):理想中的視口。這個概念最先由蘋果提出,其餘瀏覽器廠商陸續跟進,目的是解決在佈局視窗下頁面元素太小的問題,顯示在理想視口中的頁面具備最理想的寬度,用戶無需進行縮放。因此理想視窗就至關於把佈局視窗修改爲一個理想的大小,這個大小和物理視窗基本相等。

以下圖,能夠表示物理視窗和佈局視窗的關係,底部的網頁大小至關於佈局視窗,而半透明灰色區域表示物理視窗大小,看起來就像一個手機屏幕大小。 瀏覽器

圖片描述
因此若是想要在物理視窗裏面徹底展現佈局視窗裏的內容,確定要將頁面縮小。那麼縮小到多少合適呢,就須要有理想視窗,以下圖所示。
圖片描述

設置Viewport

對於移動端web頁面,能夠採用<meta>標籤對視窗的大小,縮放等進行配置,也就是以前提到的在<head>標籤內設置的<meta>的代碼以下:bash

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
複製代碼

其中,能夠配置的屬性含義以下:前端工程師

  • width:該屬性被用來控制視窗的寬度,能夠將width設置爲320這樣確切的像素數,也能夠設爲device-width這樣的關鍵字,表示設備的實際寬度,通常爲了自適應佈局,廣泛的作法是將width設置爲device-width。
  • height:該屬性被用來控制視窗的高度,能夠將height設置爲640這樣確切的像素數,也能夠設爲device-height這樣的關鍵字,表示設備的實際高度,通常不會設置視窗的高度,這樣內容超出的話採用滾動方式瀏覽。
  • initial-scale:該屬性用於指定頁面的初始縮放比例,能夠配置0.0~10的數字,initial-scale=1表示不進行縮放,視窗恰好等於理想視窗,當大於1時表示將視窗進行放大,小於1時表示縮小。這裏只表示初始視窗縮放值,用戶也能夠本身進行縮放,例如雙指拖動手勢縮放或者雙擊手勢放大。
  • maximum-scale:該屬性表示用戶可以手動放大的最大比例,能夠配置0.0~10的數字。
  • minimum-scale:該屬性相似maximum-scale,用來指定頁面縮小的最小比例。一般狀況下,不會定義該屬性的值,頁面過小將難以瀏覽。
  • user-scalable:該屬性表示是否容許用戶手動進行縮放,可配置no或者yes。當配置成no時,用戶將不能經過手勢操做的方式對頁面進行縮放。

在使用<meta>標籤設置viewport時有幾點須要注意,首先viewport只對移動端瀏覽器有效,對PC端瀏覽器是無效的,其次對於移動端瀏覽器,某些屬性也並非徹底支持,例如對於iOS的Safari瀏覽器,從10.0版本開始將不在支持user-scalable=no,因此即便設置了user-scalable=no,用戶依然能夠對頁面進行手勢操做來縮放。若是依然須要禁用,能夠參考以下代碼:

window.onload = function () {
  document.addEventListener('touchstart',  function(event) {
    // 當兩個手指操做
    if (event.touches.length > 1) {
       // 組織瀏覽器默認事件
       event.preventDefault();
    }
  });
  
  var lastTouchEnd = 0;
  document.addEventListener('touchend', function(event) {
    var now = (new Date()).getTime();
    // 判斷是不是雙擊操做,即兩次點擊間隔小於300ms
    if (now - lastTouchEnd <= 300) {
     // 組織瀏覽器默認事件
      event.preventDefault();
    }
    lastTouchEnd = now;
  }, false);
}
複製代碼

經過手勢來進行縮放是屬於瀏覽器的默認功能,上面代碼的原理就是利用event.preventDefault()方法,來禁用瀏覽器的默認事件,這樣就不能觸發這個默認的縮放功能。具體邏輯能夠將代碼運行以後看一下效果。 Viewport視窗的相關知識點是瞭解移動web適配的基礎,經過動態的設置viewport能夠實現不一樣屏幕下的頁面適配,例如對設備像素比不爲1的機型進行縮放,強制讓物理像素和CSS像素相等,代碼以下:

(function(){
    var scale = 1/window.devicePixelRatio;
    var meta = document.createElement("meta");
    meta.name = "viewport";
    meta.content = "width=device-width,initial-scale="+scale+",minimum-scale="+scale+",maximum-scale="+scale;
    document.head.appendChild(meta);
})();
複製代碼

這種方法有時候不許確,好比devicePixelRatio不爲整數的時候,會出現除不盡的狀況,那縮放的倍數就會出現很長的小數,再去算物理像素的時候就會有偏差,因此如今大部分移動web頁面採用更加完善的rem或者vw加flex的方案來進行適配。

Rem適配

Rem適配方案是當下流行而且兼容性最好的移動端適配解決方案,它支持大部分的移動端系統和機型,Rem其實是一個字體單位,即rem(font size of the root element)是指相對於根元素的字體大小的單位,簡單的說它就是一個相對單位。看到rem你們必定會想起em單位,em(font size of the element)是指相對於父元素的字體大小的單位。它們之間其實很類似,只不過一個計算的規則是依賴根元素一個是依賴父元素計算。 因此Rem適配方案的適配原理就是:將咱們以前寫px的單位換成rem單位,而後根據屏幕大小動態設置根元素<html>的font-size大小,那麼只要跟元素的font-size改變,對應的元素的大小就會改變,從而達到在不一樣屏幕下的適配的目的。

動態設置根元素font-size

使用瀏覽器瀏覽網頁時,網頁中的字體大小由根元素<html>來決定,而<html>的字體大小由瀏覽器自己決定,在不修改瀏覽器默認字體狀況下是16px,即默認狀況下1rem = 16px,可是若是採用Rem的適配方案就須要動態設置<html>的font-size。通常狀況下是根據屏幕的寬度來動態設置,即採用屏幕寬度來識別不一樣的機型,以達到對不一樣機型的適配,具體有兩種方案來設置,第一種是採用媒體查詢(Media Query),代碼以下:

@media screen and (min-width:461px){
    html{
        font-size:18px;
    }
}
@media screen and (max-width:460px) and (min-width:401px){
    html{
       font-size:22px;
    }
}

@media screen and (max-width:400px){
    html{
        font-size:30px;
    }
}
複製代碼

上面代碼中,使用screen媒體特性,來定義了3組屏幕寬度區間,當小於400px,大於401px且小於460px,大於461px,當屏幕寬度位於不一樣的區間時,則會應用上對應的<html>的font-size。 另一種則是使用Javascript動態設置<html>的font-size,代碼以下:

// 獲取屏幕視窗寬度
let htmlWidth = document.documentElement.clientWidth || document.body.clientWidth;// 獲取寬度最好有個兼容的方案,避免某些狀況下第一種獲取不到能夠選擇第二種
//獲取html
let htmlDom = document.getElementsByTagName('html')[0];
htmlDom.style.fontSize = htmlWidth / 10 + 'px';   //求出font-size
複製代碼

上面代碼中,獲得屏幕寬度後,通常要除以一個係數,這裏使用的係數是10,這樣獲得的font-size值更加靈活,適配性更強,因此實際應用當中,大多數採用的JavaScript來動態設置。若是想要實時監聽屏幕大小的變化動態修改font-size,能夠引入resize事件,代碼以下:

window.addEventListener('resize',function(){
    /*上面設置font-size的代碼*/
})
複製代碼

計算rem數值

設置完font-size以後,就能夠直接利用rem單位來給咱們的div或者其餘元素設置寬高等等的屬性了,這裏就有一個問題,咱們通常拿到的UI稿都會提供標註,這些標註通常會標識出某個元素例如按鈕,圖片具體大小數值,單位是px,而且整個UI稿都會基於一個具體的移動設備,例如iPhone6s等,能夠參考下圖所示。

圖片描述
那麼,咱們如何根據視覺稿上的px單位值轉換成對應的rem單位值呢?這裏舉一個例子,一個按鈕在視覺搞上標註的大小是:寬200px,高400px,那麼咱們根據這個來進行以下計算:

  • 以iPhone6s視覺搞來講,屏幕是375*667單位是px。
  • 根據上面JavaScript方法設置的<html>的font-size獲得是37.5px,這裏37.5px稱作rem的基準值,下面的計算會用。
  • 根據1rem=37.5px,獲得200px=5.3rem,400px=10.6rem。

根據上面的方法,咱們就能夠給按鈕元素設置rem單位了,代碼以下:

.button {
   width: 5.3rem;
   height: 10.6rem;
font-size:0.53rem;
background-color: red;
}
複製代碼

咱們給一個元素採用了rem單位來設置了寬高,那麼這個元素在不一樣機型中顯示時,因爲設置的根元素<html>的font-size大小不同,那麼rem所實際渲染出來的大小也就不同,能夠比較一下分別在Chrome開發者工具中的Device Mode中採用iPhone6s和iPhone6P運行的效果區別,如圖下圖所示。

圖片描述
如上圖所示,對於同一個按鈕,在不一樣的機型上表現出的大小是不同的,這就是rem帶來的適配效果。 固然,採用rem適配,必須針對rem基準值來將px轉換成對應的rem值,這個計算是很繁瑣的一件事情,可是這個工做能夠交給Sass[ Sass(英文全稱:Syntactically Awesome Stylesheets)是一個最初由Hampton Catlin設計並由Natalie Weizenbaum開發的一個CSS預處理器,採用類CSS語法並在最後解析成CSS的腳本語言。]來幫助咱們完成,例如能夠在Sass代碼中定義一個公式,代碼以下:

@function px2rem($px){
    $rem: 37.5;
    @return ($px/$rem) + rem;// $px表示變量,+號表示拼接,rem爲字符串至關於'rem'
}
.button {
   width: px2rem(200);
   height: px2rem(400);
   font-size: px2rem(20);
   background-color: red;
}
複製代碼

固然,上面的代碼已經不是一個標準的CSS代碼了,而是一個Sass語言的CSS代碼,不過沒有學過Sass也沒有關係,咱們只會用到Sass的不多一部分知識點。 上面代碼中,定義了一個方法,方法名爲px2rem,這個方法接收一個參數就是將要轉換的px值,而後根據rem基準值來計算。當在給元素設置寬高時,調用這個方法即px2rem(200),將須要轉換的px值做爲參數傳遞進去,這樣通過編譯後,最終獲得的就是rem單位的值了即width: px2rem(200)轉換成了width:5.3rem。 總結下來,使用Rem適配方案主要有如下幾點須要注意:

  • 首先須要有一段JavaScript腳原本動態設置根元素<html>的font-size,這段腳本通常放置在<head>標籤裏面,讓font-size更早的設置,可讓適配更早的生效。
  • 一旦頁面使用了Rem適配,那麼除特殊狀況除外(例如雪碧圖定位background-position時),頁面中凡是用到px爲單位的元素都應該改成rem單位,這樣才能作到總體適配。
  • 對於寬度比高度大不少的機型例如橫屏下的iPad以及一些手寫筆記本,是不適合採用Rem方案的,由於寬度較大會致使<html>的font-size設置不許確。另外就是一些小說網站,屏幕越小的移動設備若是用了rem單位就會致使文字就越小,就會致使看文章的時候特別費眼。

vw適配

vw其實也是一個CSS單位,相似的還有vh,vmin,vmax共四個單位,這些單位伴隨着CSS3的出現就已經有了,可是當時移動web的浪潮已經來臨,而且Rem出現的要早一些,因此不少開發人員對此並不熟悉。 和Rem適配方案相比,vw適配方案不須要使用JavaScript腳原本提早設置font-size,vw適配方案徹底基於CSS自身,這也是相對於Rem適配方案的優點所在,而且對於橫豎屏切換較爲頻繁的頁面時能夠採用vmin單位,更加靈活。咱們先來了解一下vw,vh,vmin,vmax這幾個單位,含義以下:

  • vw : 1vw 等於視口寬度的1%。
  • vh : 1vh 等於視口高度的1%。
  • vmin : 選取vw和vh中最小的那個,1vmin等於視口寬度的1%和視口高度的1%中最小的值。
  • vmax : 選取vw和vh中最大的那個,1vmax等於視口寬度的1%和視口高度的1%中最大的值。

從上面的解釋能夠看出,vw和vh這些單位也並非一個固定的值,而是根據視口寬度或者高度而變。那麼什麼是視口呢?還記得以前講解的viewport嗎,經過標籤:

<meta name="viewport" content="width=device-width">
複製代碼

設置的這個寬度就是視口寬度,而且能夠經過JavaScript中的document.documentElement.clientWidth或者document.body.clientWidth獲取到這個值,這裏就和前面講解Rem適配方案時獲取屏幕寬度時的用法是同樣的。 有些同窗會遇到例如window.innerWidth或者window.screen.width來獲取屏幕或者視口的寬度,這種方法獲取到的通常是設備的物理寬度,例如真實的分辨率或者物理像素值,這個和視口寬度不必定相等,當<meta>標籤設置viewport時,若是width=!device-width時,這種狀況下就是不相等的,因此各位在使用時仍是須要注意一下。

計算vw數值

對於vw適配方案,也是須要計算vw值的,同理咱們仍是以iPhone6的UI稿爲例子,例如一個按鈕在視覺搞上標註的大小是寬200px,高400px,那麼咱們根據這個來作以下計算:

  • 以iPhone6s視覺搞來講,屏幕是375*667單位是px。
  • 根據1vw等於視口寬度的1%,即1vw等於3.75px,獲得200px=53vw,400px=106vw(這裏取整)。

根據上面的方法,咱們就能夠給按鈕元素設置vw單位了,代碼以下:

.button {
   width: 53vw;
   height: 106vw;
   background-color: red;
}
複製代碼

和計算rem值同理,也能夠利用Sass來聲明一個方法,作px到vw的轉換,代碼以下:

@function px2vw($px) {
    $vw: 3.75;
    @return ($px/$vw)+vw;// $px表示變量,+號表示拼接,vw爲字符串至關於'vw'
}
.button {
   width: px2vw(53);
   height: px2vw(106);
   background-color: red;
}
複製代碼

不管是轉換成rem值仍是vw值,在後續的實戰項目中,均可以經過另外一種方式來更加方便的轉換。例如能夠經過構建的方式,在代碼中只須要寫px值,經過配置一些插件和工具,最終生成的項目中就是轉換好的代碼,這就是前端工程化帶來的便利。

Rem適配和vw適配兼容性

從上面的對兩種相關的適配方案講解,能夠知道vw適配方案要優於Rem適配方案的,可是沒有Rem流行就在於vw的兼容性問題,咱們從caniuse[ caniuse是一個當下流行的前端技術兼容性查詢網站,地址是:www.caniuse.com/]網站中查詢到兼容性以下。

圖片描述
圖片描述
Rem適配方案在主流瀏覽器中總體支持性98.93%,而vw適配方案在主流瀏覽器中總體支持性94.44%,而且對於Android4.4以前的機型來講vw不支持是硬傷,畢竟這部分機型的市場佔有率仍是有一部分的。因此各位在選取適配方案時,要根據本身業務的場景來選擇合適的方案,避免出現兼容性問題。

更多關於移動web相關的內容,歡迎關注課程: 《從0到1 實戰朋友圈移動Web App開發》 《移動Web App開發之實戰美團外賣》

相關文章
相關標籤/搜索