前端移動端開發之rem
前言
作為一名前端工程師,我們不僅要會PC端開發,還要會移動端開發,而且現在移動端占據主要流量,所以掌握移動端開發的技能更是必須的。
那麽進行移動端的開發,什麽是必須,我們想要的效果是什麽?
自適應。對,我們想要的效果應該是網頁上的元素能隨著窗口大小的變化而跟著同比的變化。
假如我們拿到一張750px寬的設計圖,上面有一個元素是75px寬,當這張頁面出現在只有540px寬的設備上,這個元素就得是54px寬。
如果你使用px這種固定的長度單位,在不同大小的設備上會出現什麽情況,不用我說你也知道吧。
現在手機機型五花八門,主流手機iPhone6/7/8 4.7英寸、iPhone6/7/8 Plus 5.5英寸、iPhoneX 5.8英寸等。
那麽如何讓這些機型不同大小不一致的手機呈現出我們想要的效果呢?
方案
解決移動端適配問題其實有多種方案。
1.百分比
很容易就能想到百分比能實現自適應,但百分比非常局限。
在一張網頁上,有一個元素占這個網頁寬度的一半,你很容易就想到width: 50%。
但這個元素如果出現在不知道距頁面左邊緣多少px的情況下,你一下子無法看出占多少百分比,這時候你就得去測量、去算占比,如果元素非常多的話,那就相當麻煩了。
然而,使用百分比真正的弊端在於字體大小和元素高度。
字體大小是無法通過百分比實現自適應的。
元素的高度也是一樣,一般移動端的頁面是不知道高度的,可以隨著內容無限下拉,元素的高度很難通過百分比去計算。
2.媒體查詢(@media)
使用多套CSS也可以實現移動端自適應。
但媒體查詢最適合的場景是一個網頁在PC端是一種呈現形式,在移動端是另一種呈現形式。
如果純移動端網頁(只考慮移動設備不考慮PC設備)使用媒體查詢,面對不同機型,就會有多套CSS,代碼相當冗長。
3.vw
vw是一種CSS長度單位,是相對單位。
表示相對視口寬度(Viewport Width),1vw = 1% * 視口寬度,100vw等於屏幕寬度。
它的自適應效果非常好,但是目前它的兼容性不好,特別是在移動端瀏覽器有很多兼容問題的環境下,這裏顯得特別不合適,所以不推薦。
4.rem
rem也是一種CSS長度單位,也是相對單位。
它相對於根元素(<html>)下的font-size的值,1rem = html下font-size的值。
這個單位可謂集相對大小和絕對大小的優點於一身,通過它既可以做到只修改根元素就成比例地調整所有字體大小,又可以避免字體大小逐層復合的連鎖反應。
目前,除了IE8及更早版本外,所有瀏覽器均已支持rem。
viewport
在真正使用之前,我必須介紹一下<meta name="viewport">這個元素標簽。
想必,在每一個移動端頁面,都有這麽一段代碼:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
這段代碼的意思是讓視口(viewport)的寬度等於設備的寬度,初始縮放比例為1,最小縮放比例為1,最大縮放比例為1,禁止用戶縮放。content的內容是可以配置的。
移動端瀏覽器會把網頁放在一個viewport中,
默認情況下,移動設備上的viewport是大於瀏覽器可視區域的,
所以一般會出現滾動條,這是為了能在移動設備上正常顯示那些為PC端設計的網站,移動設備上的瀏覽器都會把自己默認的viewport設為980px或其他值。
像下面這樣,在還沒有寫<meta>的情形,模擬手機瀏覽器:
所以我們必須使用<meta>元素來限制viewport的大小和縮放,一般我們都是等於設備的寬度。
必須使用<meta>元素還有一點是和rem相關的。
上面說過,rem是一種相對單位,相對於html元素下的font-size的值。
如果html元素下的font-size的值能隨著頁面的大小變化而變化,那麽rem也能做出相應的變化。
所以,如果沒有加上<meta>元素標簽這一段代碼,在不同機型大小下,html元素下的font-size的值是一直不變的,因為viewport不變,一直保持980px。
使用
“假如我們拿到一張750px寬的設計圖,上面有一個元素是75px寬,當這張頁面出現在只有540px寬的設備上,這個元素就得是54px寬。”
我們說過達到這種移動端自適應的效果最好的方法是使用rem單位。
因為1rem = html下font-size的值,如果html下font-size的值能隨著頁面的大小改變而改變,我們在代碼寫的rem就不用改變。
先約定1rem = 50px,如750px頁面,75px元素,那麽元素的width我們在代碼中設置的值就是1.5rem。當頁面大小變成540px,1rem = 36px,代碼中元素的寬度是1.5rem,所以元素現在在頁面的寬度是54px。
好,現在我們就寫一段代碼來讓html下font-size的值能隨著頁面的大小改變而改變,代碼如下:
(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 = 50 * (clientWidth / 750) + ‘px‘; }; if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false); doc.addEventListener(‘DOMContentLoaded‘, recalc, false); })(document, window);
實例
假設我們的設計師給我們一張設計圖(嗯,沒錯!就長這個樣子)
這是一張 750*1334 px的設計圖,在設計圖上量得這個黃色的矩形的長是330px,寬是190px。
因為一般設計圖都是按照iPhone6的二倍圖進行設計,所以iPhone6的實際尺寸是 375*667 px,所以黃色矩形的長應是165px,寬是95px,
而且PC端瀏覽器調試手機模式下iPhone6的尺寸也是 375*667 px。
我們約定1rem = 50px,所以黃色矩形 width: 3.3rem; height: 1.9rem;
我們的設置html下font-size的值的js代碼為
// 50是1rem等價於多少px,375是設計稿的寬度,這裏我們除以了2 docEl.style.fontSize = 50 * (clientWidth / 375) + ‘px‘;
效果:
源碼
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>rem</title> <style> div { width: 3.3rem; height: 1.9rem; background-color: yellow; } </style> </head> <body> <div></div> <script> (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 = 50 * (clientWidth / 375) + ‘px‘; }; if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false); doc.addEventListener(‘DOMContentLoaded‘, recalc, false); })(document, window); </script> </body> </html>
額外概念
在為寫這篇博客上網查資料的過程中,總結了幾個與移動端開發相關的概念。
1.物理像素physical pixel
一個物理像素是顯示器上最小的物理顯示單位。
2.設備獨立像素(也叫密度無關像素、css像素、邏輯像素)
device independent pixels(dips)
一種物理測量單位,基於計算機控制的坐標系統和抽象像素(虛擬像素),由底層系統的程序使用,轉換為物理像素的應用。
3.設備像素比device pixel ratio(dpr)
定義了物理像素和設備獨立像素的對應關系。
公式:設備像素比 = 物理像素 / 設備獨立像素 (該值也是平時手機說的幾倍屏幾倍屏的值)
4.分辨率
比如圖片是由1280個像素* 720個像素組成。
5.PPI(每英寸所擁有的像素)
PPI是用來描述屏幕的像素顯示密度。
6.DPI(每英寸打印的點數)
DPI表示每英寸打印的點數。
前端移動端開發之rem