說到前端頁面的布局方案,可以從遠(yuǎn)古時代的Table布局說起,然后來到 DIV+CSS布局,之后有了Float布局,F(xiàn)lex布局,Column布局,Grid布局等等。
而另一方面,還有一些布局概念:
1. 靜態(tài)布局
直接使用px作為單位
2. 流式布局
寬度使用%百分比,高度使用px作為單位
3. 自適應(yīng)布局
創(chuàng)建多個靜態(tài)布局,每個靜態(tài)布局對應(yīng)一個屏幕分辨率范圍。使用 @media媒體查詢來切換多個布局
4. 響應(yīng)式布局
通常是糅合了流式布局+彈性布局,再搭配媒體查詢技術(shù)使用
5. 彈性布局
通常指的是rem或em布局。rem是相對于html元素的font-size大小而言的,而em是相對于其父元素(非font-size的是相對于自身的font-size)
是的也就是我們之前做的那個是半吊子的響應(yīng)式布局。
rem布局應(yīng)該是比較適配移動端的,對移動端我還所知甚少。git上看了不少demo,自己也想動手嘗試一下。
今天配合著小demo來走一遍rem布局。
我們要明確的是:rem布局的核心是設(shè)置好根html元素的font-size。
在文章中提到了4種方案,其原理都是采用等比縮放的方式 —— 獲得目標(biāo)屏幕寬度和設(shè)計(jì)稿寬度的比,作為 rem 的基值(縮放系數(shù)),設(shè)置為html標(biāo)簽的字體大小。不同的只是在于性能取舍和書寫習(xí)慣。(那么這可能是一種主流寫法?)
可以看到方案(1)和方案(2)都結(jié)合了media query的寫法,令人頭禿的是media query有時候查詢的跨度較大,比如說
@meida (min-width:370px) 到@media (min-width:480px),這中間370~480就響應(yīng)同一個px,那么其實(shí)還是有差的,雖然說media query是新手入門一個比較簡單的方式,但不能永遠(yuǎn)用media query(我自認(rèn)為)。
當(dāng)如果實(shí)際運(yùn)用到頁面中的單位為px的時候,這里我們有一個簡單的數(shù)學(xué)計(jì)算:
目標(biāo)屏幕寬度/設(shè)計(jì)稿寬度=目標(biāo)px/rem2px
所以目標(biāo)px:
window.innerWidth/designWidth*rem2px+'px'
在這里,常用的designWidth==640px,而rem2px==100(意思是1rem==100px)。
當(dāng)如果實(shí)際運(yùn)用到頁面中的單位為%(百分比)時,同樣運(yùn)用這個數(shù)學(xué)計(jì)算,但需要注意的是,因?yàn)闉g覽器默認(rèn)的字體大小是16px,即defaultFontSize == 16px,所以我們根html的font-size的計(jì)算方式:
1rem=1*htmlFontSize*defaultFontSize
因?yàn)槠渲衕tmlFontSiz為百分比,乘上一個16px之后才是px。
所以就有,當(dāng)將根html的font-size設(shè)置為百分比時,font-size=:
window.innerWidth / designWidth * rem2px / 16 * 100? + '%'
但是,首先我們運(yùn)用px的時候,是不考慮瀏覽器默認(rèn)字體大小的,在運(yùn)用百分比的時候,我們直接將瀏覽器默認(rèn)字體大小定為16px的,也就是會遇到一個問題:
在有些 Android 手機(jī)上,瀏覽器或 webview 的默認(rèn)字體是隨著系統(tǒng)設(shè)置的字體改變的。這樣就會導(dǎo)致默認(rèn)字體大于或小于 16px。
在運(yùn)用px的時候,雖然我們的公式?jīng)]有提到16px這個defaultFontSize,但是實(shí)際上是運(yùn)用了的,無從改起(或者說我暫時沒想到辦法)。所以我們的想法是:運(yùn)用百分比,然后去獲取當(dāng)下的defaultFontSize。

以上辦法可以嵌入在js中去使用。
現(xiàn)在我們先嘗試使用手淘的flexible.min.js插件來構(gòu)造自適應(yīng)rem布局。
flexible.js是阿里團(tuán)隊(duì)開源的一個庫。使用它輕松搞定各種不同的移動端設(shè)備兼容自適應(yīng)問題。而flexible.min.js是其精簡版。
Flexible會將視覺稿分成100份(主要為了以后能更好的兼容vh和vw),而每一份被稱為一個單位a。同時1rem單位被認(rèn)定為10a。針對我們這份視覺稿可以計(jì)算出:(設(shè)計(jì)稿為750px為例)
1a = 7.5px
1rem = 75px
那么我們這個示例的稿子就分成了10a,也就是整個寬度為10rem,<html>對應(yīng)的font-size為75px:·
這樣一來,對于視覺稿上的元素尺寸換算,只需要原始的px值除以rem基準(zhǔn)值即可。例如此例視覺稿中的圖片,其尺寸是176px * 176px,轉(zhuǎn)換成為2.346667rem * 2.346667rem。
(原始px值:176px,rem基準(zhǔn)值75,176/75==2.34666667)
也就是,flexible.js通過js來調(diào)整html的字體大小。而我們之后使用css在頁面中的制作稿則統(tǒng)一使用rem這個單位來制作。
使用的方法很簡單,將下面這段代碼復(fù)制到你的頁面的頭部的script標(biāo)簽的最前面。
//designWidth:設(shè)計(jì)稿的實(shí)際寬度值,需要根據(jù)實(shí)際設(shè)置
//maxWidth:制作稿的最大寬度值,需要根據(jù)實(shí)際設(shè)置
//這段js的最后面有兩個參數(shù)記得要設(shè)置,一個為設(shè)計(jì)稿實(shí)際寬度,一個為制作稿最大寬度,例如設(shè)計(jì)稿為750,最大寬度為750,則為(750,750)
;(function(designWidth, maxWidth) {
? ? var doc = document,
? ? win = window,
? ? docEl = doc.documentElement,
? ? remStyle = document.createElement("style"),
? ? tid;
? ? function refreshRem() {
? ? ? ? var width = docEl.getBoundingClientRect().width;
? ? ? ? maxWidth = maxWidth || 540;
? ? ? ? width>maxWidth && (width=maxWidth);
? ? ? ? var rem = width * 100 / designWidth;
? ? ? ? remStyle.innerHTML = 'html{font-size:' + rem + 'px;}';
? ? }
? ? if (docEl.firstElementChild) {
? ? ? ? docEl.firstElementChild.appendChild(remStyle);
? ? } else {
? ? ? ? var wrap = doc.createElement("div");
? ? ? ? wrap.appendChild(remStyle);
? ? ? ? doc.write(wrap.innerHTML);
? ? ? ? wrap = null;
? ? }
? ? //要等 wiewport 設(shè)置好后才能執(zhí)行 refreshRem,不然 refreshRem 會執(zhí)行2次;
? ? refreshRem();
? ? win.addEventListener("resize", function() {
? ? ? ? clearTimeout(tid); //防止執(zhí)行兩次
? ? ? ? tid = setTimeout(refreshRem, 300);
? ? }, false);
? ? win.addEventListener("pageshow", function(e) {
? ? ? ? if (e.persisted) { // 瀏覽器后退的時候重新計(jì)算
? ? ? ? ? ? clearTimeout(tid);
? ? ? ? ? ? tid = setTimeout(refreshRem, 300);
? ? ? ? }
? ? }, false);
? ? if (doc.readyState === "complete") {
? ? ? ? doc.body.style.fontSize = "16px";
? ? } else {
? ? ? ? doc.addEventListener("DOMContentLoaded", function(e) {
? ? ? ? ? ? doc.body.style.fontSize = "16px";
? ? ? ? }, false);
? ? }
})(750, 750);
其中最后的兩個參數(shù)是可以設(shè)置的,第一個參數(shù)是設(shè)計(jì)稿的寬度,一般設(shè)計(jì)稿有640,或者是750,你可以根據(jù)實(shí)際調(diào)整。第二個參數(shù)則是設(shè)置制作稿的最大寬度,超過750,則以750為最大限制。
或者可以直接使用以下html模板(沒截全,看清楚script放在哪個位置,寫什么就好。)

之后再在我們編寫css的時候,統(tǒng)一使用rem作為單位來編寫。
【這里要尤其注意的是,flexible.min.js版本與手淘版本的計(jì)算rem的方法不同,該代碼版本使用的是1rem=100px的換算。·】
該版本使用的是1rem=100px的換算。該版本使用的是1rem=100px的換算。該版本使用的是1rem=100px的換算。該版本使用的是1rem=100px的換算。?
假如你有一個塊是.box{width:120px;height:80px;} 轉(zhuǎn)為rem則為.box{width:1.2rem; height:.8rem;},這樣編寫。
當(dāng)然,我們用vue的時候不用這么繁瑣。
用vue的時候,用npm先install一下flexible包,然后引入,再設(shè)置下,完事。
1.npm下載
npm i lib-flexible --save
2.main.js引入
import 'lib-flexible/flexible.js'
通過要以上兩步,就完成了在vue項(xiàng)目使用lib-flexible來解決移動端適配了。
lib-flexible會自動在html的head中添加一個meta name="viewport"的標(biāo)簽,同時會自動設(shè)置html的font-size為屏幕寬度除以10,也就是1rem等于html根節(jié)點(diǎn)的font-size。假如設(shè)計(jì)稿的寬度是750px,此時1rem應(yīng)該等于75px。假如量的某個元素的寬度是150px,那么在css里面定義這個元素的寬度就是 width: 2rem。
3.這里需要注意幾點(diǎn):
(1)檢查一下html文件的head中,如果有 meta name="viewport"標(biāo)簽,需要將他注釋掉,因?yàn)槿绻羞@個標(biāo)簽的話,lib-flexible就會默認(rèn)使用這個標(biāo)簽。而我們要使用lib-flexible自己生成的 meta name="viewport"來達(dá)到高清適配的效果。
(2)因?yàn)閔tml的font-size是根據(jù)屏幕寬度除以10計(jì)算出來的,所以我們需要設(shè)置頁面的最大寬度是10rem。
接下來就可以愉快地用rem寫css了。
藍(lán)鵝,一個個去除rem基準(zhǔn)值(這個版本里是100),除到頭禿。所以我們可以使用px2rem-loader自動將css中的px轉(zhuǎn)成rem~~~
所以我們使用 webpack 的 px2rem-loader,自動將px轉(zhuǎn)換為rem
這里我們參考了這篇文章,步驟基本相同,達(dá)到的效果沒毛病。
1.安裝
npm install px2rem-loader --save-dev
2.配置
找到 build/utils.js文件,在utils.js中添加如下配置:

找到generateLoaders方法,在函數(shù)里如下配置:

重啟后,你的項(xiàng)目寫的px全變成了rem,所以你的px按照設(shè)計(jì)稿來寫就行。
————————————————————————————————————————
Sass預(yù)處理語言可以通過函數(shù)將px轉(zhuǎn)換成rem,這樣我們編寫css的時候只需要用設(shè)計(jì)稿的px就行。
根據(jù)rem的原理,設(shè)定了HTML根元素的font-size值,只需要相應(yīng)的像素值除以font-size值即可。利用SCSS提供的@function寫出這個函數(shù)
@functionpxTorem($pixels){?
?@return$pixels / $font_size+rem;}
然后我們寫scss的時候這樣寫:(這里隨便舉例,實(shí)際上寫設(shè)計(jì)稿px)
div{
width:rem(100px);
height:rem(100px);}
編譯后,就會自然變成下面這樣:
div{
width:6.25rem;
height:6.25rem; }
let'all,基本上rem自適應(yīng)布局就是這么回事~(入門級別的寫法,求高手)