1. 程式人生 > >前端開發知識之前端移動端適配總結

前端開發知識之前端移動端適配總結

演示 等於 不同 無效 這也 sta 一個 name 物理

meta標簽到底做了什麽事情

做過移動端適配的小夥伴一定有遇到過這行代碼:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

但是,很多小夥伴只是感性的認識:噢,我加了這行代碼,然後頁面的寬度就會跟我的設備寬度一致。然而,這種理解是很片面的。那麽,這句話的本質到底是什麽呢?

不急,我們先往下面看,這裏先留個懸念。

幾個專有名詞和單位

這裏,我們先來辨析一下在適配的時候經常會遇到的一些名詞、數值單位。

首先,先來看一下物理像素。

以iphone6為例,可知道:

分辨率:1334pt x 750pt

指的是屏幕上垂直有1136個物理像素,水平有750個物理像素。

屏幕尺寸:4.7in

註意英寸是長度單位,不是面積單位。4.7英寸指的是屏幕對角線的長度,1英寸等於2.54cm。

屏幕像素密度:326ppi

指的是每英寸屏幕所擁有的像素數,在顯示器中,dpi=ppi。dpi強調的是每英寸多少點。同時,屏幕像素密度=分辨率/屏幕尺寸

接著,我們來看一下其他的單位。

設備獨立像素:設備獨立像素,不同於設備像素(物理像素),它是虛擬化的。比如說css像素,我們常說的10px其實指的就是它。需要註意的是,物理像素開發者是無法獲取的,它是自然存在的一種東西,該是多少就是多少。

設備像素比:縮寫簡稱dpr,也就是我們經常在谷歌控制臺移動端調試頂端會看到的一個值。設備像素比 = 設備像素 / css像素(垂直方向或水平方向)。可以通過JS來獲取:window.devicePixelRatio

PC和移動端不同的視口

註:以下涉及的像素均為CSS像素。並且默認不考慮縮放。

布局視口

寫過css的小夥伴應該知道,我們在 htmlbody設置 width:100%;height:100%;的時候,它並不是無效的。我們都知道 100%這種百分數應該是繼承父元素而來的。那在這裏是繼承哪裏的呢?

在PC瀏覽器中,有一個用來約束CSS布局視口的東西,又叫做初始包含塊。這也就是所有寬高繼承的由來。除去 marginpadding,布局視口和瀏覽器可視窗口寬度是一致的,同時也和瀏覽器本身的寬度一致。

但是在移動端,就大不一樣了。

以下的例子是在不加 meta標簽的前提下進行演示的。

假如我們現在做一個二八分的左右布局,那麽如果在PC端上面的話,顯示的效果非常完美,這沒什麽好說的。

那如果是在手機端呢,這裏以iphone6為例子來講解:

圖例如下:

代碼如下:

* { margin: 0; padding: 0;}html,body { height: 100%; width: 100%;}.left { float: left; width: 20%; height: 100%; background: red;}.right { float: right; width: 80%; height: 100%; background: green;}----<body> <div class="left"></div> <div class="right"></div></body>

這裏我們會看到,為什麽 body的高度是 980px,而瀏覽器的寬度只有 375px,那麽這個980px到底是從哪裏來的呢?

其實,這裏的 980px就是移動端所謂的布局視口了。

在移動端,默認的情況下,布局視口的寬度是要遠遠大於瀏覽器的寬度的。這兩個視口不同於PC端,是相互獨立存在的。為什麽呢?試想一下,如果一個網頁不對移動端進行適配,用戶進行閱讀的時候,如果默認情況下布局視口的寬度等於瀏覽器寬度,那是不是展示起來更加的不友好。也就是說,如果一個 div的寬度為20%,那麽它在布局視口寬度為 980px的時候,展示給用戶的像素還有196px,而如果寬度只有 375px的情況下,寬度只有 75px,展示的大小相差特別大。

所以,瀏覽器廠商為了讓用戶在小屏幕下網頁也能夠顯示地很好,所以把布局視口寬度設置地很大,一般在 768px~1024px之間,最常見的寬度是 980px。這個寬度可以通過document.documentElement.clientWidth得到。

視覺視口

對於視覺視口來說,這個東西是呈現給用戶的,它是用戶看到網頁區域內CSS像素的數量。由於用戶可以自行進行縮放控制,所以這個視口並不是開發者需要重點關註的。

值得註意的是,在移動端縮放不會改變布局視口的寬度,當縮小的時候,屏幕覆蓋的css像素變多,視覺視口變大,反之亦然。

而在PC端,縮放對應布局寬度和視覺窗口寬度都是聯動的。而瀏覽器寬度本身是固定的,無論怎麽縮放都不受影響。

如果對上面的寬度還是很亂,那麽這裏有一個表格可以幫助你理清思路。

以下表格橫向都以瀏覽器窗口的寬度作為基準:

對於PC端來說:

對於移動端來說:

理想視口

以上,布局視口很明顯對用戶十分的不友好,完全忽略了手機本來的尺寸。

所以蘋果引入了理想視口的概念,它是對設備來說最理想的布局視口尺寸。理想視口中的網頁用戶最理想的寬度,用戶進入頁面的時候不需要縮放。

那麽很明顯,所謂的理想寬度就是瀏覽器(屏幕)的寬度了。

所以就有了下面的這段代碼:

<meta name="viewport" content="width=device-width">

然而,這段代碼其實也並不完美,在IE瀏覽器中,由於橫屏豎屏的切換會對其造成影響,為了解決這個兼容性的問題,最後再加上一句,就有了現在的:

<meta name="viewport" content="width=device-width,initial-scale=1">

initial-scale=1 的意思是初始縮放的比例是1,使用它的時候,同時也會將布局視口的尺寸設置為縮放後的尺寸。而縮放的尺寸就是基於屏幕的寬度來的,也就起到了和width=device-width```同樣的效果。

另外,值得一提的是,我們在進行媒體查詢的時候,查詢的寬度值其實也是布局視口的寬度值。

Retina屏幕&普通屏幕,模糊的由來

dpr的具體表現

有時候我們會發現,當我們在適某一機型的時候,顯示上沒什麽問題。但是一旦我換到另外一部手機,發現出現了模糊的情況,尤其以圖片更為顯著。

其實這個問題,就是涉及到了上面講到的一個屬性:設備像素比,即我們經常說的dpr。下面先來看dpr的表現:

假設現在有一臺iphone6,那麽它的設備獨立像素是375x667,dpr為2,尺寸是4.7in,那麽物理像素就是750x1334。

同樣的我們也有一臺不知名的設備,它的設備獨立像素剛好也是375x667,尺寸也是4.7in,但是dpr為1,此時的物理像素就是375x667。

於是,它們的屏幕表現如下:

技術分享圖片

在不同的屏幕上,無論是普通屏幕還是retina屏幕,css像素所呈現的大小是一致的。(如果不理解這句話,可以寫一個2px的正方形使用谷歌控制臺移動設備調試,在不同的設備之間來回切換,你會發現大小其實是一樣的。一開始我總以為這個css像素的實際寬高因為受到dpr的影響而在不同設備上的長寬是不一致的。)

不同的是,1個css像素對應(覆蓋)的物理像素個數。

所以,如果我們想要在這兩個屏幕顯示這麽一個css樣式:

width: 2px;heigth: 2px;

在普通屏幕下,也就是dpr為1的屏幕中,1個css像素對應(覆蓋)的是一個物理像素。在retina屏幕下,1個css像素對應(覆蓋)的是4個物理像素。換句話說,就是dpr為2的設備。看下面這張圖:

淺顯的理解就是可以看作是2cmx2cm的正方形被切割成四塊,然後遇到dpr為2的時候,被切割的四塊又被分別切割成四塊,但是總面積不變。

模糊的產生

知道了1個css像素覆蓋的物理像素可能不同,就好理解為什麽會出現模糊的情況了。

這裏又講到一個名詞:位圖像素。

位圖像素是柵格圖像(如:png,jpg,gif等)最小的數據單元。每一個位圖像素都包含著一些自身的顯示信息。(如:顯示位置,顏色值,透明度等)

理論上來說,1個位圖像素對應1個物理像素,圖片才能等到完美清晰的展示。

但是上面說過,在retina屏幕上,會出現1個位圖像素對應多個物理像素。

還是以iphone6為例,1個位圖像素對應4個物理像素。由於單個位圖像素已經是最小的數據單位了,它不能再被進行切割。於是為了能夠顯示出來,就只能就近取色,從而導致所謂的圖片模糊問題。如下:

如何解決

很明顯,由於位圖像素不夠分而產生模糊的情況,解決的辦法十分簡單,就是使用跟dpr同個倍數大小的圖片。比如iphone6,一個200x300的 img標簽,原圖就要提供400x600的大小。

那麽當加載到 img標簽中,瀏覽器會自動對每1px的css像素減半,可以理解為此時還是維持著1:1的css像素:物理像素,不產生模糊。

這個做法其實就是手淘團隊在做retina適配的一個重要的原理之一,後面會講到,這裏先放著不說。

其他

反向思考一下,如果普通屏幕,也就是dpr為1的屏幕,也使用了兩倍的圖片,會發生什麽樣的情況呢?

很明顯,在普通屏幕下,200×300的 img標簽,所對應的物理像素個數就是200×300個,而兩倍圖片的位圖像素個數則是200x300x4,於是就出現一個物理像素點對應4個位圖像素點,所以它的取色也只能通過一定的算法進行縮減,顯示結果就是一張只有原圖像素總數四分之一,肉眼看上去雖然圖片不會模糊,但是會覺得有點色差。(其實就是模糊的逆向過程)

用圖片來表示就是:

這裏摘取了網上一篇博文的demo來闡述上面所說的問題。

以上是一張100x100的圖片,分別放在了100x100,50x50,25x25的容器中,在retina屏幕下面的顯示效果。

通過取色器放大鏡可以看出邊界像素點的差別:

在圖一中,邊界像素點就近取色,色值介於紅白之間,偏淡,圖片看上去會模糊(可以理解為圖片拉伸)。

在圖二中,圖片正常,很清晰。

在圖三中,邊界像素點就近取色,色值介於紅白之間,偏濃,圖片看上去有色差。

手淘團隊flexible.js布局

現今,適配手機端的傳統rem布局已經逐步被手淘團隊的一套flexible布局代替。

具體的實現方式以及細節這裏也不鋪開來說,具體參考w3cplus的一篇文章,很容易讀懂和理解。

這裏我更想分析一下flexible.js做法的意義和原因。

讀過文章之後,相信大家應該對整個開發適配的流程比較熟悉了。

假設現在要適配一個iphone6的設備。上面已經說過了iphone6的各個參數,這裏不再贅述,需要的自行上移查看。

於是:

  1. 設計師給了一個750px寬度的設計稿(註意這裏是750px而不是375px)

  2. 前端工程師用750px的這個比例開始還原

  3. 把寬高是px的轉換成rem

  4. 字體使用px而不使用rem

  5. flexible.js會自動判斷dpr進行整個布局視口的放縮

rem布局和字體的處理

從flexible.js中可見,在寬高中使用的是rem,這是為了保證在不同寬度尺寸的設備中能夠保證布局的等比例縮放。

而為什麽字體不使用rem而是采用px呢?

首先,用過rem單位的小夥伴都會發現,使用rem後由於不同的尺寸,換算之後出現各種奇奇怪怪的數值,最為明顯的就是更多的小數位,比如 13.755px之類的數值。在瀏覽器中,各瀏覽器中對小數點的計算存在偏差,而且有些帶小數的 font-size值在特定的瀏覽器顯示並不夠清晰。

其次,我們並不希望在小屏幕下面顯示跟大屏幕同等量的字體。並且如果使用rem的話,那麽由於等比例的存在,在小屏幕下就會存在小屏幕字體更小的情況,不利於我們更好的去閱讀,違背了適配的初衷。所以,對於字體的適配,更好的做法就是使用px和媒體查詢來進行適配。

所以,也就不難解釋為什麽要對 font-size進行放大的處理了,如下的sass代碼:

@mixin font-dpr($font-size) { font-size: $font-size; [data-dpr="2"] & { font-size: $font-size * 2; } [data-dpr="3"] & { font-size: $font-size * 3; }}

由於retina屏幕下dpr的不同,我們又想顯示的字體一樣大,於是就給字體再增大dpr的倍數,這樣當縮小dpr倍的時候,那麽字體也就和設計稿所示的大小一樣大了,在不同的手機中顯示的大小也是一致的。

Retina屏幕下的處理與安卓手機的適配

從flexible.js的代碼中可以知道,flexible布局僅僅只是針對iPhone進行適配,而默認所有的安卓設備都強制性設置dpr為1。

於是,因為這個緣故,很多小夥伴可能就會產生這樣的問題:為什麽安卓不用retina屏幕,安卓下面是不是就不會有模糊的問題?

其實不然,模糊的本質是因為dpr,而安卓手機不同的設備的dpr也是不盡相同的。也就是說,安卓手機下也存在模糊的情況。只不過它的屏幕不叫retina屏幕,沒有這個叫法,所以很多小夥伴都誤認為安卓手機沒有這個毛病。

那麽問題又來了?既然也有模糊的毛病,那麽為什麽安卓手機不進行適配呢?

問題就在這裏了,有興趣的小夥伴可以去看一下大中華的安卓手機,dpr參數五花八門,從1到4,連1.75、2.75這種奇葩的數字也有,所以個人覺得權衡之下,直接簡單“粗暴”把安卓手機全部設置為1,是效率和收益更高的做法。

當然,也有人進行了flexible.js的改進,就是對dpr比較正常的安卓手機進行適配,也就是說只適配dpr為整數的安卓設備。對於那些奇葩的dpr為1.75的設備直接忽略。實現這個並不難,有興趣的小夥伴們可以試下。

響應式與自適應的選擇

最後,對於響應式和自適應的區別,網上有各種各樣的解釋。

個人認為,其實沒必要把它講得那麽復雜,知乎上有個小夥伴講我覺得就很白話文:

響應式針對的是不同分辨率設備而進行的適配式設計,以利用@media規則為主要手段,而自適應則忽略@media以比例布局為主,目的是適應不同的瀏覽器窗口大小。

於是我們會發現,現今大型網站,例如說淘寶網,已經沒有做響應式了。什麽意思呢?

我們會發現,淘寶網手機端和網頁端使用的是兩個域名,也就是說,不同的客戶端已經不再共用一套dom結構了。而是區分開來做自適應。然後每次用戶訪問的時候它就根據客戶端的類型重定向。

為什麽呢?

試想一下淘寶這種大型網站,一個分頁下的商品條目特別多,並且每個商品條目的dom結構又十分復雜,而且pc端往往顯示的信息是要比手機端更多的。如果不分開做兩套,而是直接用響應式的話,那麽pc端上顯示的很多dom就要在手機端上隱藏,結果這些dom都沒有被用到,但是卻加載了。在這個流量和速度至上的時代,代碼冗余先不說,多加載的這些無用的代碼而消耗的流量,從某種意義上來說就已經損失了很多的效益。

以上,就是本文的全部啦。

文章有借鑒,借鑒的鏈接都會在這裏放出來。

前輩們的經驗和知識很寶貴,我們需要做的,是站在巨人的肩膀上,去提煉這些東西,有自己更好的理解、思考和開拓新知識面。

前端開發知識之前端移動端適配總結