摘要:設備像素比縮寫簡稱,也就是我們經常在谷歌控制臺移動端調試頂端會看到的一個值。在移動端,默認的情況下,布局視口的寬度是要遠遠大于瀏覽器的寬度的。手淘團隊布局現今,適配手機端
meta標簽到底做了什么事情
做過移動端適配的小伙伴一定有遇到過這行代碼:
但是,很多小伙伴只是感性的認識:噢,我加了這行代碼,然后頁面的寬度就會跟我的設備寬度一致。然而,這種理解是很片面的。那么,這句話的本質到底是什么呢?
不急,我們先往下面看,這里先留個懸念。
幾個專有名詞和單位這里,我們先來辨析一下在適配的時候經常會遇到的一些名詞、數值單位。
首先,先來看一下物理像素。
以iphone6為例,可知道:
分辨率:1334pt x 750pt
指的是屏幕上垂直有1334個物理像素,水平有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的寬度是980px,而瀏覽器的寬度只有375px,那么這個980px到底是從哪里來的呢?
其實,這里的980px就是移動端所謂的布局視口了。
在移動端,默認的情況下,布局視口的寬度是要遠遠大于瀏覽器的寬度的。這兩個視口不同于PC端,是相互獨立存在的。為什么呢?試想一下,如果一個網頁不對移動端進行適配,用戶進行閱讀的時候,如果默認情況下布局視口的寬度等于瀏覽器寬度,那是不是展示起來更加的不友好。也就是說,如果一個div的寬度為20%,那么它在布局視口寬度為980px的時候,展示給用戶的像素還有196px,而如果寬度只有375px的情況下,寬度只有75px,展示的大小相差特別大。
所以,瀏覽器廠商為了讓用戶在小屏幕下網頁也能夠顯示地很好,所以把布局視口寬度設置地很大,一般在768px ~ 1024px之間,最常見的寬度是980px。這個寬度可以通過document.documentElement.clientWidth得到。
視覺視口
對于視覺視口來說,這個東西是呈現給用戶的,它是用戶看到網頁區域內CSS像素的數量。由于用戶可以自行進行縮放控制,所以這個視口并不是開發者需要重點關注的。
值得注意的是,在移動端縮放不會改變布局視口的寬度,當縮小的時候,屏幕覆蓋的css像素變多,視覺視口變大,反之亦然。
而在PC端,縮放對應布局寬度和視覺窗口寬度都是聯動的。而瀏覽器寬度本身是固定的,無論怎么縮放都不受影響。
如果對上面的寬度還是很亂,那么這里有一個表格可以幫助你理清思路。
以下表格橫向都以瀏覽器窗口的寬度作為基準:
對于PC端來說:
對于移動端來說:
理想視口
以上,布局視口很明顯對用戶十分的不友好,完全忽略了手機本來的尺寸。
所以蘋果引入了理想視口的概念,它是對設備來說最理想的布局視口尺寸。理想視口中的網頁用戶最理想的寬度,用戶進入頁面的時候不需要縮放。
那么很明顯,所謂的理想寬度就是瀏覽器(屏幕)的寬度了。
所以就有了下面的這段代碼:
然而,這段代碼其實也并不完美,在IE瀏覽器中,由于橫屏豎屏的切換會對其造成影響,為了解決這個兼容性的問題,最后再加上一句,就有了現在的:
width=device-width 這句代碼可以把布局視口設置成為瀏覽器(屏幕)的寬度。
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都沒有被用到,但是卻加載了。在這個流量和速度至上的時代,代碼冗余先不說,多加載的這些無用的代碼而消耗的流量,從某種意義上來說就已經損失了很多的效益。
最后考慮到兼容性的問題,原先我們在文章頭部說到的那段代碼:
從Chrome32+版本開始是會默認禁用用戶縮放的,但是考慮到兼容大部分設備,還是要加上其他設置,讓meta標簽能夠有更好的容錯性。也就是下面這段代碼:
需要注意的是,在ios10+以上,盡管開發者設置了user-scalable=no,Safari還是允許用戶通過手勢來縮放。(安卓手機各大廠商的內置瀏覽器也逐漸開放用戶縮放,即使使用meta標簽進行設置)
解決的方法也很簡單,只需要檢測touch相關事件來阻止事件的觸發即可。
window.onload = function() { // 同時按下兩個手指 document.addEventListener("touchstart", function(event) { if(event.touches.length > 1) { event.preventDefault() } }) var lastTouchEnd = 0; // 特別注意300ms時差的設置 document.addEventListener("touchend", function(event) { var now = (new Date()).getTime(); if(now-lastTouchEnd <= 300) { event.preventDefault(); } lastTouchEnd = now; }) }
以上,就是本文的全部啦。
文章有借鑒,借鑒的鏈接都會在這里放出來。
前輩們的經驗和知識很寶貴,我們需要做的,是站在巨人的肩膀上,去提煉這些東西,有自己更好的理解、思考和開拓新知識面。
相關鏈接:
移動端適配方案(主要講解的是移動端視口方面的知識):
https://segmentfault.com/a/11...
https://segmentfault.com/a/11...
Retina屏幕下模糊的由來:
http://mobile.51cto.com/web-4...
手淘flexible.js布局:
http://www.w3cplus.com/mobile...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89099.html
摘要:并且除了常用的端,還要考慮微信端,或者是端。所以我們要有一套機制,在端上走的代碼,在端或者微信端上走端對應的代碼。對于一個從零開始的移動端項目,我總結了以上這些移動開發難點,希望之后的人能少踩點坑,站在我的肩膀上提高項目開發的效率和質量。 從零搭建移動H5開發項目實戰 前端H5的前世今身 在Pc的時代,前端技術無疑統治了大多數用戶的交互界面!而在移動為王的今天,NA開發在早期占領了大多...
摘要:并且除了常用的端,還要考慮微信端,或者是端。所以我們要有一套機制,在端上走的代碼,在端或者微信端上走端對應的代碼。對于一個從零開始的移動端項目,我總結了以上這些移動開發難點,希望之后的人能少踩點坑,站在我的肩膀上提高項目開發的效率和質量。 從零搭建移動H5開發項目實戰 前端H5的前世今身 在Pc的時代,前端技術無疑統治了大多數用戶的交互界面!而在移動為王的今天,NA開發在早期占領了大多...
閱讀 3469·2023-04-25 21:43
閱讀 3097·2019-08-29 17:04
閱讀 797·2019-08-29 16:32
閱讀 1533·2019-08-29 15:16
閱讀 2143·2019-08-29 14:09
閱讀 2731·2019-08-29 13:07
閱讀 1623·2019-08-26 13:32
閱讀 1320·2019-08-26 12:00