rem是如何實現自適應布局的?


著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
鏈接:http://caibaojian.com/web-app-rem.html
來源:http://caibaojian.com

摘要:rem是相對於根元素,這樣就意味着,我們只需要在根元素確定一個px字號,則可以來算出元素的寬高。本文講的是如何使用rem實現自適應。

rem這是個低調的css單位,近一兩年開始嶄露頭角,有許多同學對rem的評價不一,有的在嘗試使用,有的在使用過程中遇到坑就棄用了。但是我對rem綜合評價是用來做web app它絕對是最合適的人選之一。

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

為什么web app要使用rem?
這里我特別強調web app,web page就不能使用rem嗎,其實也當然可以,不過出於兼容性的考慮在web app下使用更加能突顯這個單位的價值和能力,接下來我們來看看目前一些企業的web app是怎么做屏幕適配的。

1、實現強大的屏幕適配布局:
最近iphone6一下出了兩款尺寸的手機,導致的移動端的屏幕種類更加的混亂,記得一兩年前做web app有一種做法是以320寬度為標准去做適配,超過320的大小還是以320的規格去展示,這種實現方式以淘寶web app為代表作,但是近期手機淘寶首頁進行了改版,采用了rem這個單位,首頁以內依舊是和以前一樣各種混亂,有定死寬度的頁面,也有那種流式布局的頁面。

我們現在在切頁面布局的使用常用的單位是px,這是一個絕對單位,web app的屏幕適配有很多中做法,例如:流式布局、限死寬度,還有就是通過響應式來做,但是這些方案都不是最佳的解決方法。

例如流式布局的解決方案有不少弊端,它雖然可以讓各種屏幕都適配,但是顯示的效果極其的不好,因為只有幾個尺寸的手機能夠完美的顯示出視覺設計師和交互最想要的效果,但是目前行業里用流式布局切web app的公司還是挺多的,看看下面我收集的一些案例:

1.亞馬遜:

2.攜程:

3.蘭亭

上面的網站都是采用的流式布局的技術實現的,他們在頁面布局的時候都是通過百分比來定義寬度,但是高度大都是用px來固定住,所以在大屏幕的手機下顯示效果會變成有些頁面元素寬度被拉的很長,但是高度還是和原來一樣,實際顯示非常的不協調,這就是流式布局的最致命的缺點,往往只有幾個尺寸的手機下看到的效果是令人滿意的,其實很多視覺設計師應該無法接受這種效果,因為他們的設計圖在大屏幕手機下看到的效果相當於是被橫向拉長來一樣。

流式布局並不是最理想的實現方式,通過大量的百分比布局,會經常出現許多兼容性的問題,還有就是對設計有很多的限制,因為他們在設計之初就需要考慮流式布局對元素造成的影響,只能設計橫向拉伸的元素布局,設計的時候存在很多局限性。

2.固定寬度做法
還有一種是固定頁面寬度的做法,早期有些網站把頁面設置成320的寬度,超出部分留白,這樣做視覺,前端都挺開心,視覺在也不用被流式布局限制自己的設計靈感了,前端也不用在搞坑爹的流式布局。但是這種解決方案也是存在一些問題,例如在大屏幕手機下兩邊是留白的,還有一個就是大屏幕手機下看起來頁面會特別小,操作的按鈕也很小,手機淘寶首頁起初是這么做的,但近期改版了,采用了rem。

3.響應式做法
響應式這種方式在國內很少有大型企業的復雜性的網站在移動端用這種方法去做,主要原因是工作大,維護性難,所以一般都是中小型的門戶或者博客類站點會采用響應式的方法從web page到web app直接一步到位,因為這樣反而可以節約成本,不用再專門為自己的網站做一個web app的版本。

4.設置viewport進行縮放
天貓的web app的首頁就是采用這種方式去做的,以320寬度為基准,進行縮放,最大縮放為320*1.3 = 416,基本縮放到416都就可以兼容iphone6 plus的屏幕了,這個方法簡單粗暴,又高效。說實話我覺得他和用接下去我們要講的rem都非常高效,不過有部分同學使用過程中反應縮放會導致有些頁面元素會糊的情況。

rem能等比例適配所有屏幕 上面講了一大堆目前大部分公司主流的一些web app的適配解決方案,接下來講下rem是如何工作的。

上面說過rem是通過根元素進行適配的,網頁中的根元素指的是html我們通過設置html的字體大小就可以控制rem的大小。舉個例子:

html{
font-size:20px;
}
.btn {
width: 6rem;
height: 3rem;
line-height: 3rem;
font-size: 1.2rem;
display: inline-block;
background: #06c;
color: #fff;
border-radius: .5rem;
text-decoration: none;
text-align: center;
}
Demo 上面代碼結果按鈕大小如下圖:

我把html設置成10px是為了方便我們計算,為什么6rem等於60px。如果這個時候我們的.btn的樣式不變,我們再改變html的font-size的值,看看按鈕發生上面變化:

html{
font-size:40px;
}
Demo

按鈕大小結果如下:

上面的width,height變成了上面結果的兩倍,我們只改變了html的font-size,但.btn樣式的width,height的rem設置的屬性不變的情況下就改變了按鈕在web中的大小。

其實從上面兩個案例中我們就可以計算出1px多少rem:

第一個例子:

120px = 6rem * 20px(根元素設置大值)

第二個例子:

240px = 6rem * 40px(根元素設置大值)

推算出:

10px  = 1rem 在根元素(font-size = 10px的時候);

20px  = 1rem 在根元素(font-size = 20px的時候);

40px  = 1rem 在根元素(font-size = 40px的時候);

在上面兩個例子中我們發現第一個案例按鈕是等比例放大到第二個按鈕,html font-size的改變就會導致按鈕的大小發生改變,我們並不需要改變先前給按鈕設置的寬度和高度,其實這就是我們最想看到的,為什么這么說?接下來我們再來看一個例子:

Demo

由上面兩個的demo中我們知道改變html的font-size可以等比改變所有用了rem單位的元素,所以大家可以通過chrome瀏覽器的調試工具去切換第三個的demo在不同設備下的展示效果,或者通過縮放瀏覽器的寬度來查看效果,我們可以看到不管在任何分辨率下,頁面的排版都是按照等比例進行切換,並且布局沒有亂。我只是通過一段js根據瀏覽器當前的分辨率改變font-size的值,就簡單的實現了上面的效果,頁面的所有元素都不需要進行任何改變。

到這里肯定有很多人會問我是怎么計算出不同分辨率下font-size的值?

首先假設我上面的頁面設計稿給我時候是按照640的標准尺寸給我的前提下,(當然這個尺寸肯定不一定是640,可以是320,或者480,又或是375)來看一組表格。

上面的表格藍色一列是Demo3中頁面的尺寸,頁面是以640的寬度去切的,怎么計算不同寬度下font-site的值,大家看表格上面的數值變化應該能明白。舉個例子:384/640 = 0.6,384是640的0.6倍,所以384頁面寬度下的font-size也等於它的0.6倍,這時384的font-size就等於12px。在不同設備的寬度計算方式以此類推。

Demo3中我是通過JS去動態計算根元素的font-size,這樣的好處是所有設備分辨率都能兼容適配,淘寶首頁目前就是用的JS計算。但其實不用JS我們也可以做適配,一般我們在做web app都會先統計自己網站有哪些主流的屏幕設備,然后去針對那些設備去做media query設置也可以實現適配,例如下面這樣:

html {
font-size : 20px;
}
@media only screen and (min-width: 401px){
html {
font-size: 25px !important;
}
}
@media only screen and (min-width: 428px){
html {
font-size: 26.75px !important;
}
}
@media only screen and (min-width: 481px){
html {
font-size: 30px !important;
}
}
@media only screen and (min-width: 569px){
html {
font-size: 35px !important;
}
}
@media only screen and (min-width: 641px){
html {
font-size: 40px !important;
}
}
上面的做的設置當然是不能所有設備全適配,但是用JS是可以實現全適配。具體用哪個就要根據自己的實際工作場景去定了。

下面推薦兩個國內用了rem技術的移動站,大家可以上去參考看看他們的做法,手機淘寶目前只有首頁用了rem,淘寶native app的首頁是內嵌的web app首頁。

淘寶首頁:m.taobao.com

D X:m.dx.com

最后我們再來看一看他的兼容性:

在線工具
@blinkcat,rem是可以合並雪碧圖的,viewport設置確實簡潔,但是過於粗暴,全局都進行縮放,有時候我布局並不希望全局縮放,部分布局希望不用縮放,所以使用rem,不過具體使用什么方法大家都可以根據實際情況衡量。並不是每個人都喜歡使用sass,所以在px轉rem這塊我做了一個在線轉換工具:http://520ued.com/tools/rem

REM自適應JS
具體使用方法請參考這篇文章:Rem精簡版實現自適應-優化flexible.js

//designWidth:設計稿的實際寬度值,需要根據實際設置
//maxWidth:制作稿的最大寬度值,需要根據實際設置
//這段js的最后面有兩個參數記得要設置,一個為設計稿實際寬度,一個為制作稿最大寬度,例如設計稿為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 設置好后才能執行 refreshRem,不然 refreshRem 會執行2次;
refreshRem();

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 = "16px";
} else {
	doc.addEventListener("DOMContentLoaded", function(e) {
		doc.body.style.fontSize = "16px";
	}, false);
}

})(750, 750);
部分文章參考:web app變革之rem

作為一個前端開發人員,我們的任務是將UI設計師的圖稿運用計算機語言呈現在用戶面前。而現在的設備大小尺寸不一,近年來智能手機的普及更是讓網頁的用戶大部分來源與手機,所以讓不同大小的移動端屏幕都能較好的還原設計稿就成了一個前端開發者需要解決的當務之急。我查閱了大量資料和進行了一些實踐,下面是我對移動端適配的一些認識。

首先我們來談談我們在電腦端用的字體單位px和em

在國內的網站中大多都是使用px作為字體單位,只有百度做了個可調的表率。而在大洋彼岸,幾乎所有的主流站點都使用em作為字體單位,也就是可調的。他們為什么要用em作為單位呢,主要有一下幾個原因

IE無法調整那些使用px作為單位的字體大小;
國外的大部分網站能夠調整的原因在於其使用了em作為字體單位;
Firefox能夠調整px和em,但是96%以上的中國網民使用IE瀏覽器(或內核)。

px和em概念

px像素(Pixel): 相對長度單位。像素px是相對於顯示器屏幕分辨率而言的。
__em:__是相對長度單位。相對於當前對象內文本的字體尺寸。如當前對行內文本的字體尺寸未被人為設置,則相對於瀏覽器的默認字體尺寸。

任意瀏覽器的默認字體高都是16px。所有未經調整的瀏覽器都符合: 1em=16px。那么12px=0.75em,10px=0.625em。為了簡化font-size的換算,需要在css中的body選擇器中聲明 Font-size=62.5%,這就使em值變為 16px*62.5%=10px, 這樣12px=1.2em, 10px=1em, 也就是說只需要將你的原來的px數值除以10,然后換上em作為單位就行了。

em有如下特點:
  1. em的值並不是固定的;
  2. em會繼承父級元素的字體大小。
所以我們在寫CSS的時候,需要注意兩點:
  1. body選擇器中聲明Font-size=62.5%;
  2. 將你的原來的px數值除以10,然后換上em作為單位;
  3. 重新計算那些被放大的字體的em數值。避免字體大小的重復聲明。

下面我們來談談移動端的適配方案

首先講講一個基本概念

視窗 viewport

移動前端中常說的 viewport (視口)就是瀏覽器顯示頁面內容的屏幕區域。

移動端的viewport太窄,為了能更好為CSS布局服務,所以提供了兩個viewport:虛擬的visual viewport和布局的layout viewport。

layout viewport(布局視口)

一般移動設備的瀏覽器都默認設置了一個viewport 元標簽,定義一個虛擬的layout viewport(布局視口),用於解決早期的頁面在手機上顯示的問題。iOS, Android基本都將這個視口分辨率設置為 980px,所以pc上的網頁基本能在手機上呈現,只不過元素看上去很小,一般默認可以通過手動縮放網頁。

這里是一個小demo,分別是加了和沒加頁面的效果

visual viewport(視覺視口)和物理像素

visual viewport(視覺視口)備物理屏幕的可視區域,屏幕顯示器的物理像素,同樣尺寸的屏幕,像素密度大的設備,硬件像素會更多。例如iPhone的物理像素:

iPhone5 :640 * 1136
iPhone6:750 * 1334
iPhone6 Plus:1242 * 2208

ideal viewport(理想視口)和 dip (設備邏輯像素)

ideal viewport(理想視口)通常是我們說的屏幕分辨率。

dip (設備邏輯像素)跟設備的硬件像素無關的。一個 dip 在任意像素密度的設備屏幕上都占據相同的空間。

比如MacBook Pro的 Retina (視網膜)屏顯示器硬件像素是:2880 * 1800。當你設置屏幕分辨率為 1920 * 1200 的時候,ideal viewport(理想視口)的寬度值是1920像素, 那么 dip 的寬度值就是1920。設備像素比是1.5(2880/1920)。設備的邏輯像素寬度和物理像素寬度(像素分辨率)的關系滿足如下公式:

邏輯像素寬度*倍率 = 物理像素寬度

而移動端手機屏幕通常不可以設置分辨率,一般都是設備廠家默認設置的固定值,換句話說 dip 的值就是 ideal viewport(理想視口)(也就是分辨率)的值,比如,iPhone的屏幕分辨率:

iPhone5 :分辨率 320 * 568,物理像素 640 * 1136,@2x
iPhone6:分辨率 375 * 667,物理像素 750 * 1334,@2x
iPhone6 Plus :分辨率 414 * 736,物理像素1242 * 2208,@3x

所以我們需要使用viewport元標簽控制布局

通常用到的適配代碼

這里是每個屬性的詳細介紹

width

為了是適應布局,我們一般將width設為device-width。

width=device-width 也就是將layout viewport(布局視口)的寬度設置 ideal viewport(理想視口)的寬度。網頁縮放比例為100%時,一個CSS像素就對應一個 dip(設備邏輯像素),而layout viewport(布局視口)的寬度,ideal viewport(理想視口)的寬度(通常說的分辨率),dip 的寬度值是相等的。

initial-scale

initial-scale用於指定頁面的初始縮放比例:

initial-scale=1 表示將layout viewport(布局視口)的寬度設置為 ideal viewport(理想視口)的寬度,
initial-scale=1.5 表示將layout viewport(布局視口)的寬度設置為 ideal viewport(理想視口)的寬度的1.5倍。
因為分辨率和物理像素的關系,所以我們就需要通過js來確定頁面的初始縮放比例,下面是控制初始縮放比例的代碼。后面會進行解釋

var i = e.navigator.appVersion.match(/iphone/gi) ? e.devicePixelRatio :1,
a = 1 / i,
然后我們談談rem

rem其實和em非常相似,在w3c中是這樣描述rem的

font size of the root element.

它的用法和em差不多,區別是em是針對父元素的font-size做計算,而rem是相對與根元素做計算。我們在移動端使用rem作為所有大小的單位來解決適配的問題。

我們設置根元素font-size的大小,應該是不同屏幕設置不一樣的。比如一個740大的屏幕,我們會把它的font-size設為76px;而一個370大的屏幕,我們會把它的font-size設為34px,這要根據屏幕大小而言。

所以,我們需要編寫一個js文件來適應不同的屏幕

這是某個網站的移動適配js,這里通過這個文件做一些解釋

!function(e) {
function t() {
e.rem = d.getBoundingClientRect().width / 16, d.style.fontSize = e.rem + "px";
}
var n,
i = e.navigator.appVersion.match(/iphone/gi) ? e.devicePixelRatio :1,
a = 1 / i,
d = document.documentElement,
o = document.createElement("meta");
if (e.dpr = i,
e.addEventListener("resize", function() {
clearTimeout(n), n = setTimeout(t, 300);
}, !1),
e.addEventListener("pageshow", function(e) {
e.persisted && (clearTimeout(n), n = setTimeout(t, 300));
}, !1),
d.setAttribute("data-dpr", i), o.setAttribute("name", "viewport"),
o.setAttribute("content", "initial-scale=" + a + ", maximum-scale=" + a + ", minimum-scale=" + a + ", user-scalable=no"), d.firstElementChild)
d.firstElementChild.appendChild(o);
else {
var m = document.createElement("div");
m.appendChild(o), document.write(m.innerHTML);
}
t();
}(window), document.addEventListener("DOMContentLoaded", function() {
var e = document.createElement("input");
e.type = "hidden",
e.value = '{"platform": "qq_qzone_weixin_weibo_copy","title":"","desc": "","image":"","comment": "", "url":"","callback":"shareCallback()"}',
e.id = "app_share_conf", document.getElementsByTagName("body")[0].appendChild(e);
}, !1);
把視覺稿中的px轉換成rem

我們在開發過程中拿到的設計稿都是以px作為單位的,那我們在進行移動端編程的時候該怎樣對應rem大小呢?

e.rem = d.getBoundingClientRect().width / 16
這段代碼的意思是把屏幕分成16份,根元素的font-size就等於屏幕大小/分成份數。當然我們不一定要把屏幕分成16份,比如淘寶的Flexible.js將屏幕分成10份。

縮放比例

前面已經提到,針對不同的設備,屏幕分辨率和物理像素的倍速不同所以我們要通過獲取設備來設置縮放比例。

var i = e.navigator.appVersion.match(/iphone/gi) ? e.devicePixelRatio :1,
a = 1 / i,
關於移動適配的meta標簽,我們是不用事先編寫的,通過這個js文件,將自動創建meta標簽。
————————————————


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM