1. 程式人生 > >移動端開發規範以及基礎總結(速記)

移動端開發規範以及基礎總結(速記)

移動裝置的基礎知識:

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:使用者是否可以手動縮放
3  理想視口的尺寸,螢幕的裝置畫素尺寸 佈局視口:document.document.clientWidth 視覺視口:window.innerWidth
獲取根元素的寬度:window.document.documentElement.getBoundingClienRect().width;
獲取物理尺寸和理想視口的比例:window.devicePixelRatio
(screen.width有嚴重的相容性問題,獲取有可能是裝置的寬度,也可能是理想視口的尺寸)
4 viewport的設定和rem的基準值設定。
;(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;
}