盤點移動端適配方案

盤點移動端適配方案

移動端.png

作為開發(fā)者,在手機移動端做適配的時候會出現(xiàn)很多問題:最不希望用戶看到的就是橫向滾動條。其次是文字(圖片等)的大小不能一成不變,要根據(jù)用戶設備的物理像素調節(jié)大小。

手機瀏覽器是把頁面放在一個虛擬的"窗口"(viewport)中,通常這個虛擬的"窗口"(viewport)比屏幕寬,這樣就不用把每個網頁擠到很小的窗口中(<u>這樣會破壞沒有針對手機瀏覽器優(yōu)化的網頁的布局</u>),用戶可以通過平移和縮放來看網頁的不同部分。

這就該輪到meta標簽出場了。meta標簽的作用是讓當前viewport的寬度等于設備的寬度,同時不允許用戶手動縮放。也許允不允許用戶縮放,不同的網站有不同的要求,但讓viewport的寬度等于設備的寬度,這個應該是大家都想要的效果,如果你不這樣的設定的話,就會使用那個比屏幕寬的默認viewport,也就是說會出現(xiàn)橫向滾動條;

  • 設置Viewport

一個常用的針對移動網頁優(yōu)化過的頁面的 viewport meta 標簽大致如下:

<meta name="viewport" content="width=device-width, initial-scale=1.0">
  • width

控制 viewport 的大小,可以指定的一個值,如 600,或者特殊的值,如 device-width 為設備的寬度(單位為縮放為 100% 時的 CSS 的像素)。

  • initial-scale

初始縮放比例,也即是當頁面第一次 load 的時候縮放比例。

  • user-scalable

用戶是否可以手動縮放(默認設置為no,因為我們不希望用戶放大縮小頁面)

  • minimum-scale

允許用戶縮放到的最小比例(默認設置為1.0)

  • maximum-scale

允許用戶縮放到的最大比例(默認設置為1.0)

一、rem適配

rem(font size of the root element)是指相對于根元素的字體大小的單位。簡單的說它就是一個相對單位。看到rem大家一定會想起em單位,em(font size of the element)是指相對于父元素的字體大小的單位。它們之間其實很相似,只不過一個計算的規(guī)則是依賴根元素一個是依賴父元素計算。

正是因為它適配的標準是根元素的字體大小,而不同的手機型號對于根元素的規(guī)定不同[1],這便增加了很多不必要的判斷。

二、vw適配

vw(viewpoint width),即視窗寬度,1vw等于視窗寬度的1%

計算方式(以750的設計稿為準):設計圖中元素固定的大小(px) * 100 / 750 => vw

eg : 90px轉化為vw : 90 * 100 / 750 => 12vw

如果是375的設計稿需要乘以2 : 設計圖中元素固定的大小(px) * 2 * 100 / 750 => vw

不難看出,使用的時候仍需進行大量的計算。

三、vw+rem適配

因為vw的比例需要動態(tài)地計算,而rem做移動端布局的時候剛好需要動態(tài)地改變,因此我們只要稍加計算,將根元素的字體大小換成vw即可。

  • 640的設計稿

    320px == 100vw ; 1px == 100 / 320 == 0.3125vw ; 100px == 31.25vw;

    此時設置根元素字體大小html,body{font-size:31.25vw} , => 1rem == 100px; =>1px == 0.01rem;

    所以,根據(jù)設計稿的像素計算時,只需將px除以100即可

    計算方式:元素尺寸 / 2 / 100 = rem

    320的設計稿計算方式:元素尺寸 / 100 = rem

  • 750的設計稿

    375px == 100vw ; 1px == 100 / 375 == 0.26666vw ; 100px == 26.6666vw

    出現(xiàn)了小數(shù)點后除不盡的情況……為了將結果它轉換成整數(shù) 120px == 32vw此時設置根元素字體大小html,body{font-size:32vw} , 計算方式也發(fā)生改變:元素尺寸 / 2 / 120 = rem

    375的設計稿計算方式:元素尺寸 / 120 = rem

以上面的幾種設計稿為例,尤其是750的設計稿居多,大多數(shù)情況下根據(jù)元素的尺寸 / 120 ,這么難以計算的數(shù)字,還是交給插件來做吧。以VScode中的cssrem為例:

注意:配置完參數(shù)之后,重啟軟件

cssrem.png

四、flexible.js布局(推薦)

通過flexible.js實現(xiàn)了rem自適應,有了flexible.js,我們就不必再為移動端各種設備兼容煩惱。通過rem與px的換算,把設計稿從px轉到rem。再也不用為各種設備橫行而擔憂。

rem是相對于根元素html,這樣就意味著,我們只需要在根元素確定一個px字號,則可以來算出元素的寬高。1rem=16px(瀏覽器html的像素,可以設定這個基準值),假如瀏覽器的html設為64px,則下面的元素則1rem=64px來運算。

阿里團隊開源的一個庫。使用flexible.js輕松搞定各種不同的移動端設備兼容自適應問題。

  1. 刪除viewport的meta標簽,替換為下面的JS代碼

    (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('將根據(jù)已有的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);
        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 > 768) {
                width = 768 * dpr;
            }
            var rem = width / 7.5;
            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. 以750設計稿為準,元素尺寸 / 100 = rem ; 以375設計稿為準,元素尺寸 * 2 / 100 = rem ,因為flexble中會再除以2,所以這里乘以2將其抵消。

參考博客1 前端開發(fā)博客


  1. 根字體大小:iPhone5s:12px iPhone6S:14px iPhone6P:16px ?

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 方案一: 最新方案:(隆重推薦) 1、下載MateHandler.js,并引入頁面2、head里加入 3、設置bo...
    晨光2016閱讀 920評論 0 0
  • 移動端適配方案:1)viewport(scale=1/dpr)2)rem3)flex4)vm/vh一、什么是移動端...
    puxiaotaoc閱讀 43,127評論 3 56
  • @description 該方法是用于移動端適配功能, 結合淘寶的適配方案flexible + rem 實現(xiàn)適配,...
    王小傲閱讀 450評論 0 0
  • 手淘的rem適配js flex.js ;(function(win, lib) { var doc = win.d...
    嘗了又嘗閱讀 384評論 0 0
  • 這是一篇“讀書筆記”,原文是萬維鋼老師的專欄《精英日課》的一篇文章,與題目同名。 話不多說,直接開始! 萬老師從四...
    小小Mark閱讀 466評論 3 0