這是一個系列文章,分 3 篇:
- 移動端適配 - 基礎知識篇 通過此篇理解為何有移動端適配問題
- 移動端適配 - 實踐篇 如何一步步解決圖片高清、1px邊框、佈局適配和內容適配等問題
- 移動端適配- Rem 佈局篇 以上兩篇的簡潔版
單位
CSS中的單位
相對單位
font-size相關 | 說明 |
---|---|
rem | 相對於根元素(html元素)的font-size |
em | 相對於元素的font-size的計算值 |
ex | 相對於元素字型的小寫x的高度 |
ch | 相對於元素字型中的字形“0”的寬度 |
viewport相關 | 說明 |
---|---|
vw | 相對於視口寬度 1vw = window.innerWidth * 1% |
vh | 相對於視口高度 1vw = window.innerHeight * 1% |
vmin | vw和vh中較小的值 |
vmax | vw和vh中較大的值 |
window.innerHeight
瀏覽器視窗的視口(視覺視口)高度(單位:畫素,大小是css畫素的數量),包括水平滾動條。
window.innerWidth
瀏覽器視口(視覺視口)寬度(單位:畫素,大小是css畫素的數量),包括垂直滾動條。
絕對單位
- px
- 與裝置螢幕相關
- 對於普通螢幕,通常是顯示器的一個裝置畫素(點)
- 對於印表機或高解析度的螢幕,一個CSS畫素對應多個裝置畫素
安卓中的單位
- dp
- 在定義UI佈局時使用的虛擬畫素單位,用於以密度無關方式表示佈局維度或位置
- 1dp = 160 dpi 螢幕上的1個物理畫素
- 在定義應用的 UI 時應始終使用 dp 單位 ,以確保在不同密度的螢幕上正常顯示 UI
- sp
- px
ios中的單位
- pt
- px
參考
畫素(pixel)
裝置畫素(physical pixel)
裝置畫素又稱物理畫素
(physical pixel),是顯示器中最小的物理單元,裝置能控制顯示的最小單位。 每個畫素根據作業系統的指示設定自己的顏色和亮度。
任何裝置的物理畫素數量都是固定的。
裝置獨立畫素DIP
由程式使用並控制的虛擬畫素,比如web程式設計中的CSS畫素(px)、安卓(dp)、ios系統(pt)中的裝置獨立畫素.
CSS畫素
CSS畫素是Web程式設計中的概念,瀏覽器使用的抽象單元。 通常,CSS畫素被稱為與裝置無關的畫素(DIP)。在標準密度顯示器上,1個CSS畫素對應於1個裝置畫素。
例如:
<div height="200" width="300"></div>
複製程式碼
在普通螢幕上繪製200x300裝置畫素,在retina螢幕上為保證相同的物理尺寸,相同的div將使用400x600裝置畫素,這樣在Retina螢幕上,相同物理表面的裝置畫素數量是普通螢幕的四倍。
裝置畫素與裝置獨立畫素
裝置畫素與裝置獨立畫素有一定的對應關係,我們程式設計時控制的是裝置獨立畫素,然後由相關係統轉換為物理畫素。
一個CSS畫素相當於多少個裝置畫素由螢幕特性(是否是高密度)和縮放比例決定。放大得越大,一個CSS畫素覆蓋的裝置畫素越多。
解析度
顯示器能顯示的物理畫素的數量,顯示器可顯示的畫素越多,畫面就越精細。
螢幕畫素密度(Screen density)
螢幕畫素密度是指物理表面的畫素數量,通常以每英寸畫素測量(PPI,pixel per inch)。ppi的值越高,畫質越好。
蘋果公司為其雙重密度顯示器創造了“Retina”營銷術語,聲稱人眼不再能夠將螢幕上的各個畫素與“自然”觀看距離區分開來。
要計算顯示器的螢幕畫素密度(每英寸畫素值),首先要確定螢幕尺寸和解析度。
例如,蘋果的iphone6s,畫素解析度: 1334 x 750,對角線長度4.7英寸。
那螢幕畫素密度就是:
蘋果公司認為,人類能肉眼識別的最高畫素密度是300ppi
現在也有越來越多高解析度的安卓手機(螢幕)與蘋果iPhone的視網膜顯示器相同。
根據螢幕每英寸畫素值的不同,Android系統的開發者將平板電腦和手機的螢幕分成五類:
名稱 | 顯示等級 | 每英寸畫素值 | 相似ppi的ios裝置分類 |
---|---|---|---|
LDPI @0.75x | 低等畫素密度 | 大約120ppi | |
MDPI @1x | 中等畫素密度 | 大約160ppi | 標準點@1x |
HDPI @1.5x | 高等畫素密度 | 大約180ppi | |
XHDPI @2x | 極高畫素密度 | 大約320ppi | 視網膜 @2x |
XXHDPI @3x | 超高畫素密度 | 大約480ppi | 高清視網膜 @3x |
裝置畫素比dpr
- 縮放比為1時的物理畫素解析度與CSS畫素解析度的比值
- 在js中可以通過
window.devicePixelRatio
獲取,也可以重寫window.devicePixelRatio
來更改dpr - css中可以使用媒體查詢 device-pixel-ratio
點陣圖畫素(Bitmap Pixel)
點陣圖畫素
是基於柵格的影像(JPG、PNG、GIF)中最小的單位,每個畫素都包含螢幕上的顯示資訊,如位置、顏色等,有的影像資訊還包含不透明度(Alpha Channel)。
點陣圖影像除了自有的光柵解析度,在web網頁中有一個用CSS畫素定義的抽象尺寸,web瀏覽器根據CSS設定的高度和寬度屬性在螢幕上繪製基於柵格的影像,根據CSS尺寸可能會擠壓或拉伸影像。
當在標準密度顯示器上以完整尺寸繪製光柵影像時,1個點陣圖畫素對應1個裝置畫素,影像完全保真顯示。因為點陣圖畫素不能進一步分割,在retina螢幕中,點陣圖畫素應該是標準屏上的4倍才能保真高清顯示。
通常為Retina屏提供影像的方法是通過使用HTML或CSS程式設計手段將影像容器尺寸減半。
例如,要展示 200 x 300畫素的影像(這是css畫素),可以向伺服器請求點陣圖解析度為400 x 600畫素(4倍)的影像。
<img src="https://img.meituan.net/beautyimg/0e03672ea40f4f692f193349b86aeb90299167.jpg%40400w_600h_1e_1c_1l_100q%7Cwatermark%3D0"/>
複製程式碼
img{
width:200px;
height: 300px;
}
複製程式碼
這在標準密度顯示器上,有一個下采樣
的過程。對於點陣圖畫素400x600的影像,要在200 x 300的裝置畫素上展示,需要對其進行2倍下采樣,得到(400/2)x(600/2)的解析度影像。那其實就是把 2 x 2視窗內的點陣圖畫素變成一個畫素,這個畫素點的值就是視窗內所有畫素的均值。
影像下采樣原理
對於一幅影像I尺寸為M_N,對其進行s倍下采樣,即得到(M/s)_(N/s)尺寸的得解析度影像,當然s應該是M和N的公約數才行,如果考慮的是矩陣形式的影像,就是把原始影像s*s視窗內的影像變成一個畫素。 這個畫素點的值就是視窗內所有畫素的均值: pk = ∑i∈win(k)Ii / s2
影像上取樣原理
影像放大幾乎都是採用內插值方法,即在原有影像畫素的基礎上在畫素點之間採用合適的插值演算法插入新的元素。
為了在Retina螢幕上能夠高清保真顯示影像,需要載入2倍影像。但對於標準螢幕裝置,如果同樣使用2倍影像,會有幾個問題:
- 需要下載更大的圖片資源,造成資源浪費
- 根據所使用的下采樣演算法,2倍影像在標準密度螢幕上會丟失一些銳度
這就是如何在移動端不同解析度裝置中圖片高清保真顯示的問題,不同螢幕密度的裝置應該載入不同大小的影像,保證在不同裝置上都能保真顯示。
移動端圖片高清顯示問題
CSS媒體查詢與background-image配合使用
可以通過媒體查詢的方式,對不同dpr裝置使用不同解析度的影像。
.icon {
background-image: url(example.png);
background-size: 200px 300px;
height: 300px;
width: 200px;
}
@media only screen and (-Webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icon {
background-image: url(example@2x.png);
}
}
複製程式碼
dpr查詢使用1.5而不是2,可以用相同的語句來查詢其他非Apple裝置。
這種方式主要用於使用background-image屬性顯示的影像。
優點
- 裝置僅下載合適的目標資源
- 跨瀏覽器相容
- 畫素精確控制
缺點
- 程式設計程式碼繁瑣,特別是在大型網站上
- 對於內容展示型影像顯示為其他HTML元素的背景,這在語義上是不正確的
js控制載入合適尺寸的影像
可以使用window.devicePixelRatio在Javascript中查詢dpr,比CSS更容易設定影像。 然而,由於使用JavaScript,渲染可能會延遲。
$(document).ready(function(){
if (window.devicePixelRatio > 1) {
var images = $('img');
images.each(function(i) {
var lowres = $(this).attr('src');
var highres = lowres.replace(".", "@2x.");
$(this).attr('src', highres);
});
}
});
複製程式碼
這種方式比較適合展示內容型影像。
優點
- 易於實現
- 非Retina裝置不需要下載大的圖片資源
- 畫素精確控制
缺點
- Retina裝置必須下載1倍圖和2倍圖
- 影像替換效果在Retina裝置上能體現
- window.devicePixelRatio不支援IE或Firefox。
其他方案
- 可縮放向量圖形SVG
不管使用什麼方法,光柵影像都會被點陣圖解析度限制,不是無限可擴充套件的。但向量圖形無限縮放都不會影響清晰度
<img src="sample.svg" width="300" height="200" />
複製程式碼
- 字型圖示 Icon Fonts
參考
視口
在桌面瀏覽器中只有一個視口,視口的寬度 = 瀏覽器視窗寬度。在小屏的移動裝置(寬度240px~640px)中,如果視口寬度和瀏覽器寬度一樣,那為桌面瀏覽器設計的網頁在移動端檢視時會很醜,所以移動端瀏覽器廠商會設定一個預設的移動裝置的視口寬度,在768px ~ 1024px之間,最常見的寬度是980px。
佈局視口
CSS的佈局將根據上面介紹的視口來計算,所以在移動端這就叫佈局視口
。
視覺視口
雖然移動端預設的佈局視口寬度可以讓為桌面瀏覽器設計的網頁很好的展示,但只會有一部分內容展示在可視區域,這個區域被稱為視覺視口
。使用者可以通過縮放來操作視覺視口。
理想視口
對於移動端網頁,預設的佈局視口的寬度並不是一個理想的寬度,我們不希望需要通過縮放檢視內容,所以瀏覽器廠商引進了理想視口
的概念,與理想視口寬度相同的網頁是最理想的使用者瀏覽的寬度,剛進入頁面時使用者不需要縮放。
那對於移動端網頁,我們需要設定佈局視口的寬度為理想視口的寬度。這需要在meta標籤中宣告:
<meta name="viewport" content="width=device-width"/>
複製程式碼
參考
meta標籤
上面提到了通過meta標籤宣告佈局視口的寬度。
meta標籤的常用屬性:
屬性 | 可選值 | 描述 |
---|---|---|
charset | UTF-8等 | 宣告當前文件所使用的字元編碼 |
name | author、description 、keywords、 viewport等 | 把 content 屬性關聯到一個名稱 |
http-equiv | content-type 、expire 、refresh 、set-cookie | 把content屬性關聯到HTTP頭部 |
content | name屬性相關的元資訊,格式:key=value | 定義與http-equiv或name屬性相關的元資訊 |
對於viewport元標籤格式:
<meta name="viewport" content="key=value, key=value"/>
複製程式碼
其中content內容:
width
:佈局視口寬度(數值 / device-width)(範圍從200 到10,000,預設為980 畫素)height
:佈局視口高度(數值 / device-height)(範圍從223 到10,000)initial-scale
:初始的縮放比例 (範圍從>0 到10)minimum-scale
:允許使用者縮放到的最小比例maximum-scale
:允許使用者縮放到的最大比例user-scalable
:使用者是否可以手動縮 (no,yes)
對於移動端頁面,常將佈局視口寬度設定為理想視口寬度,並禁止縮放:
<meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no"/>
複製程式碼
參考
媒體查詢
媒體查詢型別
- 媒介型別查詢
- 視口相關
- 特性相關
語法
@media 媒體型別 and (視口特性閥值){
// 滿足條件的css樣式程式碼
}
複製程式碼
媒體查詢示例
.sample {
background-image: url(sample.png);
width: 300px;
height: 200px;
}
@media only screen and (-Webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.sample {
background-image: url(sample@2x.png);
}
}
複製程式碼
更多用法參考
有收穫嗎? 看看這篇? 你可能不知道的 JavaScript 模組化野史