鄙人也偶爾做過移動端的開發,對於移動端適配剛開始就被幾個專用的名詞給嚇的不知所措,現在來看看這幾個名詞的真面目
物理畫素、邏輯畫素
- 物理畫素(裝置畫素):顯示裝置中一個最微小的物理部件。螢幕這塊物理材料上橫向和縱向共有多少個畫素點,任何裝置螢幕的物理畫素出廠時就確定了,且固定不變
- 邏輯畫素(裝置獨立畫素):程式使用的虛擬畫素(比如說CSS畫素),程式認為橫向和縱向有多少個畫素點,然後由相關係統轉換為物理畫素
iPhone5 | iPhone6 | iPhone8Plus | |
---|---|---|---|
邏輯畫素 | 568x320 | 667x375 | 736x414 |
物理畫素 | 1136x640 | 1334x750 | 2208x1242 |
高清屏和畫素比
畫素點
圖片是由很多的畫素點構成,每個畫素點顯示的色彩不一樣,構成了一副圖片。你可以想象把蒙娜麗莎放大很多倍,然後裁成大小相同的小塊,然後拼在一起,這個就是畫素點
高清屏
同樣大小的圓,裡面容納的正多邊形的邊數越多,其形狀越接近圓,面積越接近圓。類似相同尺寸的螢幕,一個電容點所容納的畫素點越多,一個點可以由更多的畫素點搭配來成像則效果當然更細膩,螢幕顯得更清晰。
畫素比
裝置畫素比簡稱為dpr,其定義了物理畫素和裝置獨立畫素的對應關係,它決定了一個點是由多少個畫素點來描繪。所以在開發的時候才會有@1、@2和@3圖片區別。
iPhone5 | iPhone6 | iPhone8Plus | |
---|---|---|---|
邏輯畫素 | 568x320 | 667x375 | 736x414 |
物理畫素 | 1136x640 | 1334x750 | 2208x1242 |
螢幕倍率 | @2 | @2 | @3 |
dpr | 2 | 2 | 3 |
視口viewport
- 佈局視口(layout):在html中一般在meta中的name為viewport欄位就是控制的佈局視口。佈局視口一般都是瀏覽器廠商給的一個值,移動端在不設定的情況下為980px。
document.documentElement.clientWidth(clientHeight) // 佈局視口的尺寸。
複製程式碼
- 視覺視口(visiual):瀏覽器可視區域的大小,即使用者看到的網頁的區域。(其寬度繼承的layout寬度)
window.innerWidth(innerHeight) // 視覺視口尺寸
複製程式碼
- 理想視口(ideal):layout-viewport = width.screen.width(邏輯畫素橫向)。
<meta name="viewport" content="width=device-width">
複製程式碼
由於以前的PC頁面尺寸比較小,手機在沒有進行viewport設定時預設的時980px,可以相容大多數情況,部分頁面頁面顯示太小,部分頁面顯示不下而出現滾動條。所以為了達到理想視口,將layout-viewport設定和手機邏輯畫素一樣大小。但是由於高清屏,設計稿一般和手機物理畫素一致,如果設定layout-viewport為邏輯畫素,手機程式只會用邏輯尺寸長度去佈局,那麼橫向只能顯示正常設計稿的1/2或1/3,就會出現滾動條。
1px問題
在理想視口的情況下,layout-viewport的尺寸大小是邏輯尺寸大小,所以CSS中的1px就是邏輯尺寸的1px,在顯示的時候,手機會根據dpr對其進行轉化,導致CSS中的1px其實對應的兩倍屏2px,三倍屏的3px,所以導致1px的線在這種情況下會變粗。
- IOS解決方案
.border { border: 1px solid #999 }
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.border { border: 0.5px solid #999 }
}
@media screen and (-webkit-min-device-pixel-ratio: 3) {
.border { border: 0.333333px solid #999 }
}
複製程式碼
- :before, :after與transform(相容)
.radius-border{
position: relative;
}
@media screen and (-webkit-min-device-pixel-ratio: 2){
.radius-border:before{
content: "";
pointer-events: none; /* 防止點選觸發 */
box-sizing: border-box;
position: absolute;
width: 200%;
height: 200%;
left: 0;
top: 0;
border-radius: 8px;
border:1px solid #999;
-webkit-transform(scale(0.5));
-webkit-transform-origin: 0 0;
transform(scale(0.5));
transform-origin: 0 0;
}
}
複製程式碼
- viewport縮放
//dpr為2時,安卓下通過flexible.js動態設定無效,initial-scale=0.5始終預設為1
<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
複製程式碼
適配方案
從1px的適配中,可以知道viewport縮放是為了消除高清屏倍率的影響。所以一般適配主要從兩方面著手:
- 利用viewport進行縮放來消除高清屏倍率的問題
- 利用rem來消除高清屏倍率的問題
- 利用rem調整不同裝置之間的邏輯尺寸不一致的問題
固定viewport為理想視口
- 固定高度,寬度自適應:
<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
複製程式碼
垂直方向使用固定的值,水平方向使用彈性佈局,元素採用定值、百分比、flex佈局等。這種方案相對簡單,還原設計稿程度較低,尺寸一般都採用百分比和固定值,不能跟隨裝置變化而調整,高清屏的設計稿尺寸要縮小1/2或1/3。
- 根據不同螢幕動態寫入font-size,以rem作為寬度單位。
var width = document.documentElement.clientWidth; // 螢幕的佈局視口寬度
var rem = width / 7.5; //750px設計稿將佈局視口分為7.5份
rem = px * 0.01; //1rem等於設計稿上的100px
在ipone6上:
width = document.documentElement.clientWidth = 375px;
rem = 375px / 7.5 = 50px;
0.75rem = 37.5px; (37.5/375=10%;佔螢幕10%)
在任意其他機型上:
width = document.documentElement.clientWidth = 420px;
rem = (375px / 7.5)*(420/375) = 420/7.5 = 56px;
0.75rem = 42px = (420/375)*37.5px
複製程式碼
利用rem來消除高清屏倍率的問題,利用rem調整不同裝置之間的邏輯尺寸不一致的問題,利用百分比還原設計圖,但是無法消除1px的影響
動態設定viewport
- 根據不同螢幕動態寫入font-size和viewport,以rem作為寬度單位。
var width = document.documentElement.clientWidth; // 螢幕的佈局視口寬度
var rem = width / 10; // 將佈局視口分為10份
var devicePixelRatio = window.devicePixelRatio;
var isIPhone = window.navigator.appVersion.match(/iphone/gi);
var dpr,scale;
if (isIPhone) {
if (devicePixelRatio >=3) {
dpr = 3;
} else if (devicePixelRatio >=2) {
dpr = 2;
} else {
dpr = 1;
}
} else {
dpr = 1;
}
scale = 1 / dpr;
在ipone6上:
width = document.documentElement.clientWidth = 750px;
rem = 750px / 10 = 75px;
1rem = 75px;
在任意其他機型上:
width = document.documentElement.clientWidth = 840px;
rem = (840px / 10)*(420/375) = 420/7.5 = 94.08px;
1rem = 94.08px = (420/375)*75px
複製程式碼
利用viewport進行縮放來消除高清屏倍率的問題,能消除1px的問題,利用rem調整不同裝置之間的邏輯尺寸不一致的問題,利用百分比還原設計圖,但是其1rem等於75px或者其他不固定尺寸不方便計算。
- vw和viewport放縮
var devicePixelRatio = window.devicePixelRatio;
var isIPhone = window.navigator.appVersion.match(/iphone/gi);
var dpr,scale;
if (isIPhone) {
if (devicePixelRatio >=3) {
dpr = 3;
} else if (devicePixelRatio >=2) {
dpr = 2;
} else {
dpr = 1;
}
} else {
dpr = 1;
}
scale = 1 / dpr;
100vw = 100%width
複製程式碼
這種方式類似於rem = 750px / 10 的方案,只不過用vw來替代了rem,但是它有一個好處就是將rem解放出來,所以rem用來設定字型的大小,在移動端可以相容使用者設定字型大小的影響。
- 根據不同螢幕動態寫入font-size和viewport,以rem作為寬度單位。為了消除這種不利的影響將上面進行修改:
var width = document.documentElement.clientWidth; // 螢幕的佈局視口寬度
var rem = width / 7.5; //750px設計稿將佈局視口分為7.5份
rem = px * 0.01; //1rem等於設計稿上的100px
var devicePixelRatio = window.devicePixelRatio;
var isIPhone = window.navigator.appVersion.match(/iphone/gi);
var dpr,scale;
if (isIPhone) {
if (devicePixelRatio >=3) {
dpr = 3;
} else if (devicePixelRatio >=2) {
dpr = 2;
} else {
dpr = 1;
}
} else {
dpr = 1;
}
scale = 1 / dpr;
在ipone6上:
width = document.documentElement.clientWidth = 750px;
rem = 750px / 7.5 = 100px;
0.75rem = 75px;
在任意其他機型上:
width = document.documentElement.clientWidth = 840px;
rem = (750px / 7.5)*(840/750) = 840/7.5 = 56px;
0.75rem = 84px = (840/750)*75px
複製程式碼
利用viewport進行縮放來消除高清屏倍率的問題,能消除1px的問題,利用rem調整不同裝置之間的邏輯尺寸不一致的問題,利用百分比還原設計圖,方便計算。
結語
終於揭開了移動端佈局的面紗,錯誤的地方望指正。