前端開發知識之前端移動端適配總結
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的小夥伴應該知道,我們在 html
、 body
設置 width:100%;height:100%;
的時候,它並不是無效的。我們都知道 100%
這種百分數應該是繼承父元素而來的。那在這裏是繼承哪裏的呢?
在PC瀏覽器中,有一個用來約束CSS布局視口的東西,又叫做初始包含塊。這也就是所有寬高繼承的由來。除去 margin
、 padding
,布局視口和瀏覽器可視窗口寬度是一致的,同時也和瀏覽器本身的寬度一致。
但是在移動端,就大不一樣了。
以下的例子是在不加 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的各個參數,這裏不再贅述,需要的自行上移查看。
於是:
-
設計師給了一個750px寬度的設計稿(註意這裏是750px而不是375px)
-
前端工程師用750px的這個比例開始還原
-
把寬高是px的轉換成rem
-
字體使用px而不使用rem
-
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都沒有被用到,但是卻加載了。在這個流量和速度至上的時代,代碼冗余先不說,多加載的這些無用的代碼而消耗的流量,從某種意義上來說就已經損失了很多的效益。
以上,就是本文的全部啦。
文章有借鑒,借鑒的鏈接都會在這裏放出來。
前輩們的經驗和知識很寶貴,我們需要做的,是站在巨人的肩膀上,去提煉這些東西,有自己更好的理解、思考和開拓新知識面。
前端開發知識之前端移動端適配總結