前言:這周工作碰到了移動端1px的問題。以前一直寫樣式也沒有特別注意著一點。還有就是rem的原理。這些其實就是比較常見的移動端適配問題。現階段比較主流的適配方案有二種。一種是
flexible + rem
,另一種是vw
下面我們來看一下具體情況
1、基本概念
在瞭解具體方案原理前,我們先來看一下一些基本概念:
1.1、物理畫素(physical pixel)
物理畫素又被稱為裝置畫素,他是顯示裝置中一個最微小的物理部件。每個畫素可以根據作業系統設定自己的顏色和亮度。
1.2、裝置獨立畫素(density-independent pixel)
裝置獨立畫素也稱為密度無關畫素,可以認為是計算機座標系統中的一個點,這個點代表一個可以由程式使用的虛擬畫素(比如說CSS畫素),然後由相關係統轉換為物理畫素。(老早在沒有 retina 屏之前,裝置獨立畫素與物理畫素是相等的)
1.3、CSS畫素
CSS畫素是一個抽像的單位,主要使用在瀏覽器上,用來精確度量Web頁面上的內容。一般情況之下,CSS畫素稱為與裝置無關的畫素(device-independent pixel),簡稱DIPs。
1.4、裝置畫素比(device pixel ratio)
裝置畫素比簡稱為dpr,其定義了物理畫素和裝置獨立畫素的對應關係。它的值可以按下面的公式計算得到:
裝置畫素比 = 物理畫素 / 裝置獨立畫素
複製程式碼
在JavaScript
中,可以通過window.devicePixelRatio
獲取到當前裝置的dpr
。而在CSS中,可以通過-webkit-device-pixel-ratio
,-webkit-min-device-pixel-ratio
和 -webkit-max-device-pixel-ratio
進行媒體查詢,對不同dpr
的裝置,做一些樣式適配(這裡只針對webkit核心的瀏覽器和webview)
因此在iphone 6、7、8 的 dpr 為 2的裝置中,一個裝置獨立畫素便為 4 個物理畫素,因此在 css 上設定的 1px 在其螢幕上佔據的是 2個物理畫素,0.5px 對應的才是其所能展示的最小單位。
1.5、rem
簡單的理解,rem
就是相對於根元素<html>
的font-size
來做計算。而我們的方案中使用rem
單位,是能輕易的根據<html>
的ont-size
計算出元素的盒模型大小。而這個特色對我們來說是特別的有益處。
2、flexible實現方案
瞭解了前面一些相關概念之後,接下來我們來看實際解決方案。淘寶有一個名叫lib-flexible的庫,而這個庫就是用來解決H5頁面終端適配的。 我們把螢幕分成10等分,那麼
- 物理畫素為 750 = 375 * 2,那麼 10rem = 750px,1rem = 75px;
- 物理畫素為 1125 = 375 * 3,那麼 10rem = 1125px,1rem = 112.5px ;
- 物理畫素為 1242 = 414 * 3, 那麼 10rem = 1242px,1rem = 124.2px;
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
複製程式碼
2.1、1px的物理畫素的解決方案
由此我們得到一個1px畫素的解決方案。viewport 的 initial-scale 具有縮放頁面的效果。對於 dpr=2 的螢幕,1px壓縮一半便可與1px的裝置畫素比匹配,這就可以通過將縮放比 initial-scale 設定為 0.5=1/2 而實現。以此類推 dpr=3的螢幕可以將 initial-scale設定為 0.33=1/3 來實現。
<meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5">
複製程式碼
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
複製程式碼
3、視口單位適配方案
將視口寬度 window.innerWidth 和視口高度 window.innerHeight 等分為 100 份,且將這裡的視口理解成 idealviewport 更為貼切,並不會隨著 viewport 的不同設定而改變。
- 1、vw : 1vw 為視口寬度的 1%
- 2、vh : 1vh 為視口高度的 1%
- 3、vmin : vw 和 vh 中的較小值
- 4、vmax : 選取 vw 和 vh 中的較大值
如果設計稿為 750px,那麼 1vw = 7.5px,100vw = 750px。其實設計稿按照設麼都沒多大關係,最終轉化過來的都是相對單位,上面講的 rem 也是對它的模擬。
跟之前一樣的痛點,我們仍然需要花費大量不必要的計算時間去把標註圖中的px轉換為vw,有沒有類似於postcss-px2rem的工具呢?很榮幸能再次站在巨人的肩膀上,已經有大神寫了了類似的PostCss外掛 postcss-px-to-viewport
自己學習時的一點小總結,如有問題,歡迎指正。