前端頁面的適配使用rem換算---rem詳解
為什麼要使用rem
僅用於學習,違者必究!!!
之前有些適配做法,是通過js動態計算viewport的縮放值(initial-scale)。
例如以螢幕320畫素為基準,設定1,那螢幕375畫素就是375/320=1.18以此類推。
但直接這樣強制頁面縮放過於粗暴,會導致頁面圖片文字失真模糊。
Px是相對固定單位,字號大小直接被定死,所以使用者無法根據自己設定的瀏覽器字號而縮放,em和rem雖然都是相對單位,但em是相對於它的父元素的font-size,頁面層級越深,em的換算就越複雜,而rem是直接相對於根元素,這就避開了很多層級關係。移動端新型瀏覽器對rem的相容很好,可以放心使用。
通用換算和一些坑
有時我們會看到有些使用rem的頁面裡會先給頁面根元素一個樣式:
html {font-size: 62.5%; /*10 ÷ 16 × 100% = 62.5%*/}
為什麼是62.5%?
大多數瀏覽器的預設字號是16px,因此1rem=16px,這樣不方便我們px和rem的換算,假設1rem=10px,那麼100px=10rem,25px=0.25rem。這樣就好換算很多,於是就有了上面的10/16。
如果是640的設計稿,需要除以2轉化為和iphone5螢幕等寬的320。所以設計稿px單位/2/10轉為rem。之後再媒體查詢設定每個螢幕大小的font-size百分比,頁面會根據上面設定的根font-size適配。
看到這裡是不是覺得一切很完美?然而,這裡面有兩個深坑:
1.我看了網上很多關於rem的資料,基本都說瀏覽器的預設字號就是16px,然後直接定義font-size:62.5%。但是,rem屬於css3的屬性,有些瀏覽器的早期版本和一些國內瀏覽器的預設字號並不是16px,那麼上面的10/16換算就不成立,直接給html定義font-size: 62.5%不成立。
2.chrome強制字型最小值為12px,低於12px按12px處理,那上面的1rem=10px就變成1rem=12px,出現偏差(下面給demo)。
解決方案: 將1rem=10px換為1rem=100px(或者其它容易換算的比例值);不要在pc端使用rem。
那麼上面的頁面根元素樣式要改為:
html {font-size: 625%; /*100 ÷ 16 × 100% = 625%*/}
再用本工廠總結得出的各解析度媒體查詢換算:
@media screen and (min-width:360px) and (max-width:374px) and (orientation:portrait) { html { font-size: 703%; } } @media screen and (min-width:375px) and (max-width:383px) and (orientation:portrait) { html { font-size: 732.4%; } } @media screen and (min-width:384px) and (max-width:399px) and (orientation:portrait) { html { font-size: 750%; } } @media screen and (min-width:400px) and (max-width:413px) and (orientation:portrait) { html { font-size: 781.25%; } } @media screen and (min-width:414px) and (max-width:431px) and (orientation:portrait){ html { font-size: 808.6%; } } @media screen and (min-width:432px) and (max-width:479px) and (orientation:portrait){ html { font-size: 843.75%; } }
至此,坑填完。設計稿px換算直接/100即可得到rem值。
更精準健壯的換算
然而,上面的625%大法除了有相容性問題,也無法很好地根據不同設計稿精準適配,不是我們的最佳選擇。網易和淘寶分別有自己的一套適配方法,適配性也很完美。
-
網易手機端:基準值: 可以看到,無論頁面以哪種手機比例縮放,body的width都是7.5rem。很明顯,目前網易的手機端設計稿是基於iPhone6,750(設計師給的設計稿是物理解析度,會是我們寫樣式的邏輯解析度的兩倍,如果給的設計稿是640,那麼是基於iPhone5,320),且基準值是100px(750/7.5=100)。這個基準值很關鍵,後面的css換算,都和這個基準值有關。動態font-size: 我們看到圖1、圖2、圖3的font-size都有根據螢幕大小而動態改變,可以推算出公式:
螢幕寬度/設計稿rem寬度=頁面動態font-size值(如:375/7.5=50)
獲取到這個值,再賦給html元素的style:
document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + ‘px‘;
這樣就設定好了每個頁面的根fonts-size,因為rem單位是基於根font-size,因此只要確定一種設計稿對應手機的換算,其餘螢幕尺寸均可自動適配。
上面我們得出設計稿換算rem的基準值是100,因此只需要把設計稿上的px值除以100即為我們要的rem值。
> Px/100=rem,所以100px=1rem,25px=0.25rem
-
淘寶手機端: 大名鼎鼎的Flexible
資料引用
很多大神包括我們公司同事都有對此適配方案做了解析,所以我這邊簡單綜述:
引入: 直接引用阿里的CDN檔案(或下載到本地引入)
<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
設定: 頁面不要設定 。Flexible會自動設定每個螢幕寬度的根font-size、動態viewport、針對Retina屏做的dpr。
換算: 假設拿到的設計稿和上述網易的一樣都是750,Flexible會把設計稿分為10份,可以理解為頁面width=10rem,即1rem=75px,所以根font-size(基準值)=75px。
之後的css換算rem公式為:
px/75=rem,所以100px=100/75=1.33rem,50px=50/75=0.66rem
換算工具
顯然,可以看出px與rem的換算因為基準值的不同而有些複雜,甚至需要藉助計算器的輔助。在這裡推薦一個換算神器:cssrem
安裝好之後,做一些設定
px_to_rem - px轉rem的單位比例,假設拿到設計稿750,基準值是75,此處就設75
max_rem_fraction_length - px轉rem的小數部分的最大長度。預設為6。
available_file_types - 啟用此外掛的檔案型別。[".css", ".less", ".sass", ".scss"]。
上述三種換算方案的步驟和優劣
- 通用方案
1、設定根font-size:625%(或其它自定的值,但換算規則1rem不能小於12px)
2、通過媒體查詢分別設定每個螢幕的根font-size
3、css直接除以2再除以100即可換算為rem。
優:有一定適用性,換算也較為簡單。
劣:有相容性的坑,對不同手機適配不是非常精準;需要設定多個媒體查詢來適應不同手機,單某款手機尺寸不在設定範圍之內,會導致無法適配。
- 網易方案
1、拿到設計稿除以100,得到寬度rem值
2、通過給html的style設定font-size,把1裡面得到的寬度rem值代入x document.documentElement.style.fontSize = document.documentElement.clientWidth / x + ‘px‘;
3、設計稿px/100即可換算為rem
優:通過動態根font-size來做適配,基本無相容性問題,適配較為精準,換算簡便。
劣:無viewport縮放,且針對iPhone的Retina屏沒有做適配,導致對一些手機的適配不是很到位。
網易rem方案:
前提:
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
優勢:
不用管DPR,只需知設計稿寬度
已知:
假設現有iPhone6設計稿,寬750px,其中一元素寬150px;
根據DPR值,iPhone6的DPR值為2,我們可得其中該元素的顯示尺寸:
真實顯示CSS值:
現在我們用網易方案來解決這個問題:
首先我們取1rem = 100px為參考值(這個值可以隨便取,為何取這個值容後解答)
可知body的寬度:
又因為body的寬度為7.5rem,由“網易公式”可得:
Html的font-size為:
Dw為deviceWidth,即裝置寬度,這是整個方案裡唯一動態改變的值。
現我們已知設計稿為iPhone6,又知iPhone6的裝置寬為375px,
這時候我們再回頭看:
html當前裝置的font-size:
且:
可知,無形中這步已幫我們作了DPR換算;750px的設計稿,顯示在375px的螢幕要怎樣轉換。
前面我們取了1rem = 100px,可得該元素寬:150px = 1.5rem,
又知rem為其他元素相對根元素(html)的大小,
所以可得當前元素寬度的真實css顯示值為:1.5rem*50px = 75px;(這裡的75px就跟我們前面理想得到的75px不謀而合了)。
這邊我們把這個運算再拆解來看:
現再回頭看:就可以知道為什麼當時要取100px為參考值,取這個值的意義就是為了方便運算。
總結:
我們只需以iPhone6的設計稿(當前主導的機型),750px寬完成一套頁面,當去到其他裝置時,因為我們用的都是rem值,只需要通過JS動態獲得當前的dw,再通過動態獲取的dw改變html的font-size值,頁面的其他元素也會因為html的改變而進行等比例縮放。
步驟:
1.根據設計稿尺寸完成頁面;
2.設定meta,控制視口寬度,讓頁面以1:1比例渲染頁面
3.動態設定html的font-size;
4.把各元素的px值除以100轉換為rem(字型除外)
網易方案關鍵程式碼:
設定視口:
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
動態設定html的font-size:
document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + 'px';
- 手淘方案
1、拿到設計稿除以10,得到font-size基準值
2、引入flexible
3、不要設定meta的viewport縮放值
4、設計稿px/ font-size基準值,即可換算為rem
優:通過動態根font-size、viewpor、dpr來做適配,無相容性問題,適配精準。
劣:需要根據設計稿進行基準值換算,在不使用sublime text編輯器外掛開發時,單位計算複雜。
Demo
下面看看demo
設計稿:基於iPhone5,寬度640。
那麼在開發模式,iphone5是320,所有數值均是設計稿一半大小。
期望效果:在iPhone5中,box1寬高50px,box2寬高125px,字型15px。其他螢幕終端自動適配。
可以看出,基於chrome iPhone5的除錯,box1寬高是60,box2寬高是150。出現了誤差,就是上文提到字號最小值強制12px的原因。
比例正常。
3、網易方案
比例正常。
4、手淘方案
比例正常(Retina屏做了縮放)。
到底用哪種換算方案呢?
每個人評判的標準不同。但個人更傾向flexible,動態計算viewport和針對iphone手機的dpr縮放使得頁面適配更加精確,而且手淘頁面使用者訪問量比網易頁面大很多。
移動端有用px的時候嗎?
有。當你的頁面圖片或者某一元素比例要固定,不想進行任何縮放時,rem就不適合了,這時候用px單位,能保證該元素不會因縮放而失真模糊。