聊聊自己移動端布局的經(jīng)驗

2018/01/22更新

之前的rem方式在頁面加載的時候會有個重置css的過程,導(dǎo)致了初始化的時候會出現(xiàn)頁面從小變大的閃爍

以下是另一種方法,比較完善

scss文件

@charset "UTF-8";


/* 設(shè)計圖寬度 
如設(shè)計稿750,分10份诡宗, 1rem = 75px
base:https://github.com/amfe/lib-flexible */
$baseWidthRate: 36;    //如設(shè)計稿是360px的話,就是36

/* px轉(zhuǎn)換為rem */
@function r($num) {
    @return $num / $baseWidthRate + rem;
}


/* === 全局變量配置 === */
$base-font-size          : r(14) !default; /* // 字號 */
$base-font-family        : "Microsoft YaHei",Tahoma, Arial, "Helvetica Neue", Helvetica, sans-serif !default; /* // 字體族 */


js文件(放在head)

/*!
 * from: https://github.com/amfe/lib-flexible
 */
;
(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標(biāo)簽來設(shè)置縮放比例');
        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 {
            // 其他設(shè)備下苹享,仍舊使用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;
     
        var rem = width / 10;

        if(window.__max_html_width_) {
            rem = Math.min(__max_html_width_, rem);
        }

        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'] = {}));

完善的方法其實主要在初始的js這塊双絮。
完善后的方法寫scss的時候,也跟上面的一樣得问,可以根據(jù)設(shè)計稿的尺寸來寫囤攀,如:

div{
  width:r(100);  //設(shè)計稿量的寬度是100px
}

=========================================================================
之前的文章
=========================================================================

移動端布局,相信很多人都有自己的一套兼容的方式椭赋。這里我也聊聊自己的經(jīng)驗抚岗。

一、百分比布局

我最開始的是用百分比布局的哪怔,這樣的做法的話是比較費時間的宣蔚,有些細節(jié)的地方還需要用媒體查詢來做兼容。做起來挺費時間认境,而且對于設(shè)計稿的還原也不好胚委。所以這里>也不怎么推薦。

二叉信、固定的設(shè)備寬度

在做移動開發(fā)的時候很多人都會加上viewport的配置亩冬,
那么固定設(shè)備寬度的布局就是根據(jù)這個來設(shè)置的,將viewport里面的寬度width設(shè)置成設(shè)計稿的寬度硼身,也就是說原本是width=device-width硅急,即寬度為設(shè)備的寬度,假如在iphone6上顯示的時候佳遂,那么頁面的寬度就是375px; 當(dāng)我們將width設(shè)置成設(shè)計稿的寬度的营袜,假如設(shè)計稿是750px,而我們的css也按設(shè)計的尺寸來做丑罪,例如一個圖片是200px*200px荚板,那么在css上也是寬高都是寫200px,也就是1:1的比例凤壁。那么在375px的手機上顯示的時候,就會縮小2倍顯示跪另,以此類推拧抖,在320px的寬度的時候,就會縮小2.3倍顯示免绿,在414px的寬度的時候就會縮小1.8倍唧席。
這樣的寫法是會比較好的還原設(shè)計稿,而且速度也會比較快针姿,但是這樣也有缺點袱吆,在縮>小的時候有些設(shè)備會比較模糊,因為你強行將設(shè)備放大了距淫。

三绞绒、rem布局

我現(xiàn)在常用的移動端布局主要是用rem布局,這個應(yīng)該是比較多人使用的榕暇,也是比較流行的蓬衡。使用rem布局優(yōu)點是可以適應(yīng)多個屏幕 ,也比較好的還原設(shè)計稿彤枢。在有些地方需要一屏顯示完設(shè)計稿的時候狰晚,可能需要用到vh,或是百分比。
rem布局簡單來說就是根據(jù)頁面的font-size的大小來設(shè)置頁面元素的屬性;

例如缴啡,我在iphone6的屏幕375px的時候font-size是20px,
頁面有個圖片是115*115壁晒,那么就是 115/20 = 5.75rem,如下圖

_T3%O4)V4WU7(F)MG7B7}BF.png

那么在iphone4的320px寬度下,圖片應(yīng)該是多大呢
我們可以根據(jù)剛剛頁面寬度跟fontsize的比例來計算
375/20=320/x,x ≈17px
所以320寬度的font-size應(yīng)該是約為17px业栅,顯示圖片的大小就是
17*5.75 = 97.75px
也就是縮小成這樣

IDCE49PMCCBEUVX)7KQ_9`W.png

好秒咐,入正題了
假設(shè)我們的設(shè)計稿是750px的(我現(xiàn)在做的一般都是750px);我們需要用js動態(tài)的計算設(shè)備寬度對應(yīng)的font-size的值,這里我設(shè)置320px的時候是16px,以此為基礎(chǔ)(現(xiàn)在>一般最小的設(shè)備寬度就是320px)碘裕,以下是具體的代碼:

(function (doc, win) {
  var docEl = doc.documentElement,
  resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
  recalc = function () {
  var clientWidth = docEl.clientWidth;
  if (!clientWidth) return;
  docEl.style.fontSize = 16 * (clientWidth / 320) + 'px';
};
if (!doc.addEventListener) return;
  win.addEventListener(resizeEvt, recalc, false);
  doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);

那么在375px的寬度下携取,font-size就是375/32016 = 18.75;
如果設(shè)計稿上有個圖片是200px
200px,那么在375px的設(shè)備上圖片的寬度應(yīng)該換成多少rem呢帮孔,這里我們算一下雷滋,
設(shè)圖片在375px的寬度是x,那么750/200 = 375/ x;x = 100; 圖片寬度即為 100/18.75約為5.33rem,這個換算的過程我們可以交給sass文兢,或是less去編譯晤斩。這樣我們就很方便的使用了。
下面是我常用的rem布局的sass代碼

//基礎(chǔ)font-size
$font:16;
//設(shè)計稿寬度
$screen:750;
@function px2rem($n){
@return #{$n/($screen*$font/320)}rem
}
//例如 設(shè)計稿寬度200px 那么可以寫 width = px2rem(200);可以自動換算成rem;

如果文章有問題歡迎大家多多吐槽
參考文章:《設(shè)備像素比devicePixelRatio簡單介紹

原文地址:
http://www.jamielhf.cn/?p=173

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末姆坚,一起剝皮案震驚了整個濱河市尸昧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旷偿,老刑警劉巖烹俗,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異萍程,居然都是意外死亡幢妄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門茫负,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蕉鸳,“玉大人,你說我怎么就攤上這事忍法〕背ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵饿序,是天一觀的道長勉失。 經(jīng)常有香客問我,道長原探,這世上最難降的妖魔是什么乱凿? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮咽弦,結(jié)果婚禮上徒蟆,老公的妹妹穿的比我還像新娘。我一直安慰自己型型,他們只是感情好段审,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著闹蒜,像睡著了一般寺枉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嫂用,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天型凳,我揣著相機與錄音,去河邊找鬼嘱函。 笑死甘畅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的往弓。 我是一名探鬼主播疏唾,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼函似!你這毒婦竟也來了槐脏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤撇寞,失蹤者是張志新(化名)和其女友劉穎顿天,沒想到半個月后堂氯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡牌废,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年咽白,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸟缕。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡晶框,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出懂从,到底是詐尸還是另有隱情授段,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布番甩,位于F島的核電站侵贵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏对室。R本人自食惡果不足惜模燥,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掩宜。 院中可真熱鬧蔫骂,春花似錦、人聲如沸牺汤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽檐迟。三九已至补胚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間追迟,已是汗流浹背溶其。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留敦间,地道東北人瓶逃。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像廓块,于是被迫代替她去往敵國和親厢绝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容