移動設備的基礎知識:
1 ios設備:
px:物理,分辨率相關,硬件設備。分辨率越大顯示的細節越豐富。
pt:邏輯,連接物理和軟件的中介。pt,point
ppi:每英寸px的數量 ,視網膜屏是ppi超過300的屏幕,iphone4開始
1.1 蘋果設備以及分辨率
設備
|
屏幕尺寸
|
分辨率(pt)
|
Reader
|
分辨率(px)
|
渲染後
|
PPI
|
iPhone 3GS
|
3.5吋
|
320x480
|
@1x
|
320x480
|
163
|
|
iPhone 4/4s
|
3.5吋
|
320x480
|
@2x
|
640x960
|
330
|
|
iPhone 5/5s/5c
|
4.0吋
|
320x568
|
@2x
|
640x1136
|
326
|
|
iPhone 6
|
4.7吋
|
375x667
|
@2x
|
750x134
|
326
|
|
iPhone6 Plus
|
5.5吋
|
414x736
|
@3x
|
1242x2208
|
1080x1920
|
401
|
2 android設備:
px:同上
dp:同上pt
sp:測量空間點密度的單位,單位英寸上點的個數
dpi:同上ppi
2.1 安卓屏幕尺寸關係:
1 1dp=1px mdpi(常見分辨率: 320*480)
1.5 1dp=1.5px hpi(常見分辨率:480*800)
2 1dp=2px xhdpi(常見分辨率:720*1280)
3 1dp=3px xxhdpi(常見分辨率:1080*1920)
4 1dp=4px xxxdpi(常見分辨率:2560*1440)
3 pt和px的對應關係以及常見設備:
1倍:1pt=1dp=1px(mdpi、iPhone 3gs)
1.5倍:1pt=1dp=1.5px(hdpi)
2倍:1pt=1dp=2px(xhdpi、iPhone 4s/5/6)
3倍:1pt=1dp=3px(xxhdpi、iPhone 6)
4倍:1pt=1dp=4px(xxxhdpi)
4 DPR與分辨率的關係:
css中的px等同於pt,是虛擬的點,邏輯單位。不同的縮放比,pt(css像素)佔的實際像素不一樣。
css中像素px / 縮放比=實際的像素px
舉例:(設置相同的px樣式,在不同的設備上相識效果)
上圖很明顯的說明,設置相同px在不同設備上的顯示效果。
有兩點需要分清:
1 我們所說的顯示效果實際上物理世界的顯示效果,也就是說換算成尺寸,最直觀的效果。
2 這種顯示的差異,實際上是不同設備對css px的理解不同造成的。也就是說在不同的設備上此css px不同於彼css px
怎麼解決這種差異?
1 統一css px設備之間的px的解釋,css中1px對應實際設備的1px。
2 在1的基礎上,構建邏輯尺寸。bing go......,解決問題:)。兩個問題都統一了之後,就很容易解決這個問題了。仔細想想,我們所謂看到的
顯示效果一致,是不是就是寬度高度的比例一致,也就是物理尺寸中的寬度和高度等比。
解決方式rem
這種解決方式,也就是說在dpi和ppi之間構建一個統一的邏輯單位。
背景知識:
1 rem(相對於根元素的尺寸)。
2 viewport
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1,user-scalable=no,initial-scale"> width:控制 viewport 的大小,可以指定的一個值,如果 600,或者特殊的值,如 device-width 爲設備的寬度(單位爲縮放爲 100% 時的 CSS 的像素)。 height:和 width 相對應,指定高度。 initial-scale:初始縮放比例,也即是當頁面第一次 load 的時候縮放比例。 maximum-scale:允許用戶縮放到的最大比例。 minimum-scale:允許用戶縮放到的最小比例。 user-scalable:用戶是否可以手動縮放
獲取根元素的寬度:window.document.documentElement.getBoundingClienRect().width;
(screen.width有嚴重的兼容性問題,獲取有可能是設備的寬度,也可能是理想視口的尺寸)
;(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); //未設置meta屬性的時候 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'); //TODO:添加width屬性,修改,需要測試 //metaEl.setAttribute('content',isAndroid ? 'width=device-width, ' : '' + '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); } } //初始化rem function refreshRem(){ //獲取根元素的寬度 var width = docEl.getBoundingClientRect().width; //>540 1080*s1920 /* 這個540其實是個經驗值,或者最大值,這個經驗是怎麼得出來的呢? 目前主流手機最大的css像素尺寸,是540(比如devicePixelRatio爲2,分辨率是1080x1920的手機),所以用了這個經驗值。 這樣可以讓在ipad橫屏這種情況下瀏覽無線頁面,不至於因爲拉伸適配後體驗太差。 */ if (width / dpr > 540) {//處理橫屏的頁面拉伸,寬度>1080的情況下,以1080爲準 width = 540 * dpr; } var rem = width / 10;//寬度10等分 docEl.style.fontSize = rem + 'px'; flexible.rem = win.rem = rem; } //重置的時候刷新 //var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'; 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); // body上設置12 * dpr的font-size值,爲了重置頁面中的字體默認值,不然沒有設置font-size的元素會繼承html上的font-size,變得很大 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'] = {}));
4 設計圖和rem的轉化:
750px寬度的設計圖,基礎單位 a = 750/10; 把a看成1rem,30*40px=30/75 * 40/75 = 0.4*0.53rem
5 字體的特別說明:
較寬的設備當然希望顯示字數更多,用rem不好,可以根據縮放比,設置字體的大小。
標準(中等屏幕@2):30px----->3倍縮放比 ,30px/2*3=45px---->1倍的縮放比,30px/2=15px;
5 手動轉換計算還是自動計算
可以用less混合,當然只是相對簡單了。sass應該會更好。
@p2r:720/10;//設計圖設置 .px4dpr(@pro,@val){//根據dpr的變化調整px,這是以中等分辨率750px設計圖爲準 [data-dpr="1"] &{ @{pro}:@val/2; } [data-dpr="2"] &{ @{pro}:@val; } [data-dpr="3"] &{ @{pro}:@val/2*3; } } .px2rem(@pro,@val){//px計算rem ,設計圖高度30px=> px2rem(height,30rem) @{pro}:@val/@p2r; }