背景
移動前端適配一直困擾很多人,我自己也是從最初的媒體查詢,到后來的百分比,再到padding-top這種奇巧淫技,再到css3新單位vw這種過渡轉變 但這些都或多或少會有些問題,直到使用了動態rem 才真正不再在適配這個問題上發愁 只因為叫動態rem 是因為他是真正意義上隨着屏幕的大小來變化的。
rem
rem官方解釋是 font size of the root element 字面意思就是 根元素的font-size值 也就是rem是相對於元素的
如下代碼
<html>
<meta charset="utf-8"/>
<head>
<style>
html{ font-size:10px;}
.p1{font-size:1rem;}
.p2{ font-size:2rem;}
</style>
</head>
<body>
<p class="p1">這是一個1rem字體</p>
<p class="p2">這是一個2rem的字體</p>
</doby>
</html>
從最終效果可以看出文檔中元素的字體大小是基於html根元素的 p1的font-size為10px p2的font-size是20px
viewport
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
在移動開發時我們都會有上面這段代碼
- viewport :虛擬窗口大小
- width: 控制viewport大小 可以自己設定值如320px(很少用) 一般設置為device-width(設備寬度)
- initial-scale 初始縮放比例 即頁面初次加載時的縮放比例默認為1
- maximum-scale:用戶可縮放到的最大比例
dpr(device pixel ratio)
設備像素比dpr
要了解這一概念還得清楚另外兩個概念
-
設備物理像素
通俗的講設備屏幕有多少個可以閃爍的點 是一個具體的概念 比如iphone6橫向就有750個可以改變顏色的點 類似與電視機 如果家里有10年前買的大頭電視,你趴在屏幕前仔細看能看到一個個RGB的點 這就是設備的物理像素 -
設備獨立像素
設備獨立像素是一個虛擬的概念,如程序中的css 比如我們將一個div寬度設置為10像素 那么在pc上系統會將這個div顯示在屏幕的10個點上
dpr = 設備物理像素/設備獨立像素
程序中的1px占據設備上的幾個最小物理點可以這么理解
iphone3G 設備物理像素320個點 設備獨立像素320px 那么dpr就是1
iphone6 設備物理像素750個點 設備獨立像素375px 那么dpr就是2
也就是我們css中寫的1px其實不等於設備實際上的那1px 也可能等於設備上的2px
根據dpr我們就可以靈活的在移動端縮放頁面比例
可以通過window.devicePixelRatio來獲取dpr
動態rem
通過上面的rem,viewport,以及dpr我們就可以完成我們的終極適配了,告別死板寫法 不再這樣寫死 我們知道了設備的dpr就可以明確的知道縮放多少,而且這樣還解決了很難解決的1px橫線的問題
我們需要這樣一段js代碼
(function (doc, win) {
console.log("dpr:"+win.devicePixelRatio);
var docEle = doc.documentElement,
isIos = navigator.userAgent.match(/iphone|ipod|ipad/gi),
dpr=Math.min(win.devicePixelRatio, 3);
scale = 1 / dpr,
resizeEvent = 'orientationchange' in window ? 'orientationchange' : 'resize';
docEle.dataset.dpr = dpr;
var metaEle = doc.createElement('meta');
metaEle.name = 'viewport';
metaEle.content = 'initial-scale=' + scale + ',maximum-scale=' + scale;
docEle.firstElementChild.appendChild(metaEle);
var recalCulate = function () {
var width = docEle.clientWidth;
if (width / dpr > 640) {
width = 640 * dpr;
}
docEle.style.fontSize = 20 * (width / 750) + 'px';
};
recalCulate()
if (!doc.addEventListener) return;
win.addEventListener(resizeEvent, recalCulate, false);
})(document, window);
- 獲取設備dpr
- 算出縮放比例 scale = 1/dpr
- 創建meta以及屬性
- 將scale值賦給initial-scale,maximum-scale
- meta插入到文檔中
- 創建屏幕大小改變重新計算函數並監聽
最終效果
使用sass同步psd
當我們拿到psd的時候可能要把psd的圖尺寸轉換為rem,之前一個同事有一個很好的方法可以完全按照psd的的尺寸來書寫,但要用到sass,使用sass可以大大提高開發效率,下面是sass的一個mixin方法將rem和px做了轉換
如下hotcss.scss
@function px2rem( $px ){
@return $px*750/$designWidth/20 + rem; //這句是不是感覺很熟悉 這句其實跟上面的那段js是對應的
}
$designWidth : 750; //如設計圖是750
在我們的style.scss中
@import 'px2rem.scss';
$designWidth : 750; //如設計圖是750
.banner{width:px2rem(300)}//如設計稿上的banner是300px 就免去計算環節
參考文檔
https://segmentfault.com/a/1190000003690140
https://github.com/imochen/hotcss
http://div.io/topic/1092
http://www.w3cplus.com/css/A-pixel-is-not-a-pixel-is-not-a-pixel.html