一、設備像素比 dpr (devicePixelRatio)
首先進行概念的一些解釋:
1、物理像素(又稱硬件像素)(physical pixel)
一個物理像素是顯示器上最小的物理顯示單元,每一個像素都有自己的顏色值和亮度。
同一個設備,它的物理像素是固定的,即一個設備的分辨率是固定的。
//計算公式:
//物理像素 = 邏輯像素 × 設備像素比
2、邏輯像素 dpi (又稱css像素、設備獨立像素)(density-independent pixel)
邏輯像素是指css樣式中使用的邏輯像素,也可以說是設備的寬高。
iphone4之前的手機邏輯像素數和邏輯像素數是相等的,但是由於視網膜設備(Retina屏)的出現,邏輯像素與物理像素之間有了不同的倍數對等關系。
//獲取方法
document.documentElement.clientWidth //iphone6 => 320
document.documentElement.clientHeight //iphone6 => 667
3、設備像素比 dpr (devicePixelRatio)
設備像素比 = 物理像素 / 邏輯像素
//js獲取方法
window.devicePixelRadio //iphone6 =>2
注意點:
(1)在fireFox及ie中不支持window.devicePixelRatio
(2)在同一設備不同瀏覽器中,window.devicePixelRatio值可能不同,這是由於不同的瀏覽器中css像素數不同
4、像素密度 ppi (pixels per inch)
每英寸中顯示的像素數,通常使用ppi來作為像素密度的單位;計算公式: 對角線像素個數 / 屏幕尺寸
對角線像素個數計算:(物理像素長² + 物理像素寬²)開根


不同手機物理像素、邏輯像素及像素比:

手機名稱
|
像素分辨率(px)
|
倍率
|
邏輯分辨率(pt)
|
物理尺寸(英寸)
|
屏幕密度(ppi)
|
DPI
|
i6 plus
|
1242*2208
|
@3x
|
414*736
|
5.5
|
401
|
154
|
I6
|
750*1334
|
@2x
|
375*667
|
4.7
|
330
|
163
|
I5s
|
640*1136
|
@2x
|
320*568
|
4
|
330
|
163
|
I5
|
640*1136
|
@2x
|
320*568
|
4
|
330
|
163
|
I4
|
640*960
|
@2x
|
320*480
|
3.5
|
330
|
163
|
I3GS
|
320*480
|
@1x
|
320*480
|
3.5
|
163
|
|
android
|
240*320
|
@0.75
|
320*420
|
120
|
||
android
|
320*480
|
@1x
|
320*480
|
160
|
||
android
|
480*800
|
@1.5x
|
360*500
|
240
|
||
android
|
640*960
|
@2x
|
320*480
|
320
|
||
android
|
540*960
|
@1.5x
|
360*640
|
360
|
||
android
|
720*1280
|
@2x
|
360*640
|
360
|
||
android
|
1080*1920
|
@3x
|
360*640
|
360
|
|
|
綜合以上幾個概念,以Iphone6舉例說明:設備寬高(即邏輯像素)為:375×667 ,dpr為2,物理像素為 750×1334
//css樣式
width:1px;
height:1px;


相同尺寸下,普通屏幕 VS Retina 屏,css像素所呈現的物理尺寸(大小)是一致的,不同的是一個css像素所對應的物理像素的個數不一致:
普通屏幕:css像素:物理像素 = 1:1
retina屏: css像素:物理像素 = 1:4
即4個物理像素顯示一個css像素;
二、圖片高清顯示
首先了解一下圖片的顯示規則:
位圖像素:一個位圖像素是柵格圖像最小的數據單元。每個位圖像素都包含自身的顯示信息,如色值,透明度等
理論上,當位圖像素對應物理像素時,圖片才能清晰展示。
例如:img標簽,css像素為200*300,普通屏幕下對應物理像素為200*300,retina屏幕對應物理像素為400*600:
(1)當在retina屏中,使用200*300@1x圖片時,由於每個單位的位圖像素不可分割,只能就近取色,從而導致retina屏圖片模糊;使用兩倍圖片@2x,如200*300的img標簽,使用400*600的圖片,這樣retina屏幕下,物理像素:位圖像素 = 1:1,圖片清晰
(2)如果在普通屏下使用@2x圖片,一個物理像素對應4個位圖像素,它的取色需要一定的算法,顯示結果就只有原圖像素總數的4分之一(這個過程叫downsampling),圖片雖然不會模糊,但是會少一些銳利度或者色差;同樣會造成資源浪費


最好的解決方案:不同的dpr下,使用不同尺寸的圖片。
(1)可以通過媒體查詢或者js進行控制,拼接不同的url
(2)img標簽,設置srcset屬性
//srcrest
以最合適的src去匹配不同屏幕(高分屏低分屏如Retina;大屏小屏)
//
2x、3x 表示目標屏幕的像素密度
<
img
src
="source.jpg"
srcset
="source_2x.jpg 2x, source_3x.jpg 3x"
>
//400w、600w表示目標瀏覽器的寬度的限度,如瀏覽器寬度550w時,匹配600w的src
<
img
src
="source.jpg"
width
="100%"
srcset
="source_400.jpg 400w, source_600.jpg 600w, source_1280.jpg 1280w"
>
二、移動端適配之rem
適配前提:
<meta
name=
"viewport"
content=
"initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width"
>
設配原理:使用rem單位進行移動端布局適配,原理是針對不同手機屏幕尺寸和dpr動態的改變根節點html的font-size大小
1、js方法實現
(1)引入flexible.js,改變根元素font-size
;
(
function
(win
,
lib) {
var
doc = win.document
;
var
docEl = doc.documentElement
;
var
metaEl = doc.
querySelector
(
'meta[name="viewport"]'
)
;
var
flexibleEl = doc.
querySelector
(
'meta[name="flexible"]'
)
;
var
dpr =
0
;
var
scale =
0
;
var
tid
;
var
flexible = lib.flexible || (lib.flexible = {})
;
if
(metaEl) {
console.
warn
(
'將根據已有的meta標簽來設置縮放比例'
)
;
var
match = metaEl.
getAttribute
(
'content'
).
match
(
/initial\-scale=([\d\.]+)/
)
;
if
(match) {
scale =
parseFloat
(match[
1
])
;
dpr =
parseInt
(
1
/ scale)
;
}
}
else if
(flexibleEl) {
var
content = flexibleEl.
getAttribute
(
'content'
)
;
if
(content) {
var
initialDpr = content.
match
(
/initial\-dpr=([\d\.]+)/
)
;
var
maximumDpr = content.
match
(
/maximum\-dpr=([\d\.]+)/
)
;
if
(initialDpr) {
dpr =
parseFloat
(initialDpr[
1
])
;
scale =
parseFloat
((
1
/ dpr).
toFixed
(
2
))
;
}
if
(maximumDpr) {
dpr =
parseFloat
(maximumDpr[
1
])
;
scale =
parseFloat
((
1
/ dpr).
toFixed
(
2
))
;
}
}
}
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
;
}
docEl.
setAttribute
(
'data-dpr'
,
dpr)
;
window.dpr = dpr
;
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)
;
}
}
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
;
}
win.
addEventListener
(
'resize'
,
function
() {
clearTimeout
(tid)
;
tid =
setTimeout
(
refreshRem
,
300
)
;
}
,
false
)
;
win.
addEventListener
(
'pageshow'
,
function
(e) {
if
(e.persisted) {
clearTimeout
(tid)
;
tid =
setTimeout
(
refreshRem
,
300
)
;
}
}
,
false
)
;
// if (doc.readyState === 'complete') {
// doc.body.style.fontSize = 12 * dpr + 'px';
// } else {
// doc.addEventListener('DOMContentLoaded', function(e) {
// doc.body.style.fontSize = 12 * dpr + 'px';
// }, false);
// }
refreshRem
()
;
flexible.dpr = win.dpr = dpr
;
flexible.
refreshRem
=
refreshRem
;
flexible.
rem2px
=
function
(d) {
var
val =
parseFloat
(d) *
this
.rem
;
if
(
typeof
d ===
'string'
&& d.
match
(
/rem$/
)) {
val +=
'px'
;
}
return
val
;
}
flexible.
px2rem
=
function
(d) {
var
val =
parseFloat
(d) /
this
.rem
;
if
(
typeof
d ===
'string'
&& d.
match
(
/px$/
)) {
val +=
'rem'
;
}
return
val
;
}
})(window
,
window[
'lib'
] || (window[
'lib'
] = {}))
;
(2)css使用rem為單位
css代碼中如何還原視覺稿尺寸:視覺稿一般均為二倍視覺稿,例如:以iphone6(設備尺寸375*667)做設計標准,高清設計稿為750 * 1334,html的font-size會被設置為 75px
方法一:利用sass/less @mixin計算
@mixin px2rem($attr,$value){
$attr:($value / 75) * 1rem
}
p{ //設計稿 300* 300 的元素
@include px2rem(width,300);
@include px2rem(height,300) ;
}
方法二:打包工具 postcss-px2rem
css代碼中按照設計稿尺寸編寫,css文件利用打包工具,打包為rem單位
//gulpfile.babel.js
//具體使用方法請參考官網
px2rem({
remUnit
:
75 //設計稿尺寸/10
})
,
注意:
使用rem為單位,1px邊框轉化為rem后,在andriod等版本手機,由於實際計算邊框寬度不足1px,所以,邊框不顯示;
解決方法:(1)增加邊框寬度,經實測2.5px邊框,ios和andriod手機效果兼容性更好
(2)在sass文件中,在不需要轉化rem的地方,添加注釋 /*no*/
.
testDiv
{
border
:
1
px solid red
;
/*no*/
height
:
100
px
;
line-height
:
100
px
;
font-size
:
75
px
;
}
2、css媒體查詢實現
html{
font-size:32px;
}
@media
(
min-device-width
:
320
px
){
html
{
font-size
:
32
px
;
}
}
@media
(
min-device-width
:
375
px
){
html
{
font-size
:
37.5
px
;
}
}
@media
(
min-device-width
:
414
px
){
html
{
font-size
:
41.4
px
;
}
}
缺點:根據設備寬度媒體查詢設置根元素font-size,不夠准確,只能設置某一范圍,賦予相同字號
版權聲明:本文為博主原創文章,未經博主允許不得轉載。 http://www.cnblogs.com/zuozuo-blog/
參考文章:https://www.cnblogs.com/jingwhale/p/5741567.html
https://blog.csdn.net/a0405221/article/details/78913714