移動端前端適配
- 什麼是前端適配
從ui展示層面上:
我們期望不同尺寸的裝置,頁面可以自適應的展示或者進行等比縮放,從而在不同的尺寸的裝置下看起來協調或者差不多。
從程式碼實現層面上:
我們希望前端適配可以用用盡可能簡潔的程式碼來實現,最好一套程式碼實現相容所有裝置,而不是對每個或者每種裝置都寫一套方案,不是次次都選用最無奈的方案(android和ios分開便編寫)
2.關鍵字
2.1 viewport/視口
通俗的講,移動裝置上的viewport就是裝置的螢幕上能用來顯示我們的網頁的那一塊區域,但不一定是我們可見的區域,具體來說,分為三種。
2.1.1 visual viewport
visual viewport :可見視口。就是移動裝置上可以被我們看見的部分,寬度在移動端通過window.innerWidth
獲得(僅限移動端,pc上哪怕事故chrome模擬也會有不用的結果)。
2.1.2 layout viewpot
layout viewpot:佈局視口
如果吧pc上的頁面放到移動端,以iphone8為例,如果只展示為可見視口的寬度(375px),那麼頁面會被壓縮的特別窄而顯示錯亂,所以移動瀏覽器就決定預設情況下吧viewport設為一個較寬的值比如980px,這樣的華即使是那些問桌面設計的網站也能在移動瀏覽器正常顯示了
2.1.3 ldeal viewpot
ldeal viewpot:理想視口,其實就是裝置的可見區域面和可見視口一致
設定ldeal viewpot 的好處是,只要按照ldeal viewpot 來設計樣式搞,使用者就不用能最完美的檢視網站的內容--既不用左右滑動,也不用放大縮小。
設定理想視口:
<meta name="viewpot" content='width=device-width,inital-scale=1.0 maximun-scale=10,user-scalabie=0'/>
這段程式碼的意思是將佈局視口的寬度設定為裝置寬度 初始縮放比例為1 最大縮放比例為1,使用者不能縮放。
2.2
2.2.1 物理畫素
物理畫素:一個物理畫素是顯示器(手機螢幕)上最小的物理顯示單元,在作業系統的排程下,每一個裝置畫素都有自己的顏色值和亮度值。
2.2.2 裝置獨立畫素
裝置獨立畫素:又稱為css畫素,就是我們日常程式碼中使用的畫素,瀏覽器內的一切長度都是以css畫素為單位的,css畫素的單位是px。
2.2.3 裝置畫素比
裝置畫素比(簡稱dpr)定義了物理畫素和裝置獨立畫素的對應關係,比如說對於 ios的retina屏,一個裝置獨立畫素就對應4個物理畫素,這樣的設計可以適應畫面更加清晰銳利
3.業界的解決方案
3.1rem的解決方案
dpr一致時,px在不同的螢幕尺寸上會展示為定寬,這樣導致我們的頁面可能會出現滾動條或者佔不滿的情況,而通過rem來設定div的寬高,可以保證頁面可以通過調整html的font-size來整體放大或者縮小,從而達到不管螢幕寬度是多少,頁面都能完美展示的效果。
例如,針對750*1334的設計搞:
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
<script>
document.documentElement.style.fontSize = window.innerWidth / 7.5 + 'px';
</script>
這樣,所有的裝置的寬度都是7.5rem,只需要把設計稿上的px值除於100,就可以得到相應的rem值了,
3.2 flexible.js
flexible.js 是阿里團隊開發的前端適配方案,也是用的rem的方案。那麼第一種方法其實已經能解決前端適配問題了,為啥阿里還要開發一個flexible?
在第一種方法中,dpr=1時沒有問題 但在dpr=2或者更高的手機螢幕上 因為物理畫素的增加,存在小於1px的顯示空間。如果採用第一種方法,因為它統一對scale設定為1 那麼我們想把要實現0.5px,就只能tranform的方式,如果又多個樣式,程式碼就會變得很麻煩。
.scale{
position: relative;
}
.scale:after{
content:"";
position: absolute;
bottom:0px;
left:0px;
right:0px;
border-bottom:1px solid #ddd;
-webkit-transform:scaleY(.5);
-webkit-transform-origin:0 0;
}
阿里的flexible方案充分考慮了這種情況,動態的設定了fontsize和scale,cnger使得css中的1px等於物理畫素中的1px,在ios下得到最清晰的體驗。
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,對於2和3的屏,用2倍的方案,其餘的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他裝置下,仍舊使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
最終在iphone8下頁面的header被設定為:
<meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">
具體的大家可以看《使用Flexible實現手淘H5頁面的終端適配》
另外需要指出的一點是:Flexible將頁面分成了100份,頁面的寬度是10rem,對於750的設計稿,我們需要用相應的px數除以75來得到。手動計算是愚蠢的,不同的編譯器都可以下載pix2rem外掛(可以直接寫px然後自動轉換為相應的rem值),直接使用sass或者postcss打包也能達到同樣的功能。
總結一下上面兩種rem方法,
主要思想為: 根據dpr的值來修改html的font-size,從而使用rem實現等比縮放 根據dpr的值來修改viewport實現1px的線 但是Flexible也有它的侷限性,
具體表現為: 不能與響應式佈局相容 對Android沒有做處理,導致1px和backgroudImage還要額外做處理的問題[4]
所以我們有了第三種解決方案——vw。
3.3 vw
vw是基於Viewport視窗的長度單位,在CSS3中和Viewport相關的單位有四個,
分別為vw、vh、vmin和vmax。
vw: 是Viewport’s width的簡寫,1vw等於window.innerWidth的1%
vh:和vw類似,是Viewport’s height的簡寫,1vh等於window.innerHeihgt的1%
vmin: vmin的值是當前vw和vh中較小的值
vmax: vmax的值是當前vw和vh中較大的值
其實vw的方案的寫法和flexible方案的寫法一致——因為flexible其實就是用hack的手段模擬了vw的實現而已。
具體寫法:針對750px的設計稿,將相應的px值除以75就是vw的值。
因為此方法不會改變可見視口的寬度,所以可以和media query通用了,
另外,也支援了Android上高解析度屏的展示。 儘管在某些Android機型上還存在相容問題,我們也可以使用Viewport Units Buggyfill,具體見《如何在Vue專案中使用vw實現移動端適配》