最近在重構公司的一個移動端項目,除了須要對新項目進行前端技術棧的搭建外,還須要考慮的一個重要問題就是移動端適配,關於移動端適配的理解我以前一直是處於一種比較朦朧的狀態(知其然而不知其因此然),因此最近又作了進一步的學習,在該博文中談談我對移動端適配的理解。html
在這篇博文中,我會先對移動端設備的一些基礎概念作一些解釋,包括設備獨立像素、設備像素比和 viewport ,而後在此基礎上對移動端適配作深刻的說明,最後是探究移動端適配的解決方案。前端
首先讓咱們來了解一下關於移動設備中的各個概念:瀏覽器
設備獨立像素(dip)也稱爲邏輯像素、密度獨立像素,指獨立於設備的用於邏輯上衡量像素的單位。sass
設備像素比(dpr)指的是物理像素與設備獨立像素的比例。在程序中則能夠經過 window.devicePixelRatio 來獲取,該屬性是隻讀的,但不是常量,對瀏覽器的一些操做會改變這個值。bash
那麼各個移動設備的設備像素比是怎麼得出來的呢?iphone
設備像素比是跟該移動設備的屏幕像素密度有關的。通常來說,設備像素比是屏幕像素密度除以 160 的整數倍,即 dpr = Math.floor(dpi / 160) = Math.floor(√(縱向物理像素點數²+橫向物理像素點數²) / 屏幕尺寸 / 160) 。函數
如 iphone 6 尺寸爲 4.7 英寸,屏幕分辨率爲 1334 * 750,那麼咱們能夠得出 iphone 6 的設備像素比爲:Math.floor(√(1334²+750²) / 4.7/160) = 2。佈局
前面說到,設備像素比指的是物理像素與設備獨立像素的比例,因此在知道了移動設備的設備像素比以後,咱們即可以得出該移動設備的設備獨立像素,即設備獨立像素 = 物理像素 / 設備像素比。學習
如 iphone 6 的橫向分辨率是 750,設備像素比是 2,那麼能夠得出 iphone 6 的邏輯寬度(即以設備獨立像素來計算的移動設備的寬度)是 375px 。字體
viewprot 指的是移動設備瀏覽器中放置頁面的一個虛擬的窗口,該窗口可大於或小於移動設備的可視區域。
通常移動設備默認都是 viewprot 大於其可視區域,這樣不會破壞沒有針對移動設備優化的網頁的佈局,用戶能夠經過平移和縮放來看網頁的其餘部分,大部分移動設備默認的 viewport 爲 980px(這裏的 px 指的就是設備獨立像素)。
咱們在進行移動端頁面的重構時,常常會加上以下一句代碼:
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
複製代碼
這句代碼的做用是將移動設備的 viewport 設置爲該設備的邏輯寬度,同時初始縮放值爲 1 最大縮放值爲1,而且不容許用戶進行縮放。
讓咱們來看一下 viewport 中的屬性:
當咱們把 viewport 中的 width 設置爲 width-device 時,viewport 的寬度等於移動設備的邏輯寬度,而若是設置 initial-scale 爲 1 也會獲得相同結果。通常來說咱們會同時設置這兩個屬性,當這兩個屬性由於值不一樣而產生不一樣的效果時,瀏覽器則會取得二者中較大的值。
下面舉個例子來幫助理解 viewport 屬性的做用:
<style>
html,body{
margin:0;
padding:0;
}
.box{
width:100px;
height:100px;
background:blue;
}
</style>
<div class="box"></div>
複製代碼
在谷歌瀏覽器中以 iphone 6 的調試效果以下:
能夠看到,在沒有加上 viewport 屬性的狀況下,iphone 6 中 viewport 的默認值是 980px,前面說過,這個是以設備獨立像素來計算的,也就是和咱們平時在樣式代碼中寫的 px 是同樣的,代碼中定義了一個寬高都爲 100px 的藍色塊,因此從橫向上來看的話,藍色塊在屏幕中佔了 100/980,如圖所示。
而若是咱們設置了 viewport 屬性的話:
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
複製代碼
效果以下:
能夠看到,在加上了 viewport 屬性後,移動設備的 viewport 寬度被設置成了 device-width,即該移動設備的邏輯寬度 ,在 iphone 6 中 device-width 值爲 375px,因此從橫向上來看的話,藍色塊在屏幕中佔了 100/375,如圖所示。
前面咱們已經理解了設備獨立像素、設備像素比和 viewport 的一些概念,那麼要深刻地去理解移動端適配,咱們須要先弄清楚設備像素比的做用是什麼。
舉一個最容易理解的例子。iphone 3 和 iphone 4 的屏幕尺寸是同樣的,可是 iphone 3 的屏幕分辨率是 480 * 320,而 iphone 4 的屏幕分辨率是 960 * 640,iphone 4 的橫縱向分辨率分別是 iphone 3 橫縱向分辨率的兩倍。
假設 iphone 3 和 iphone 4 的設備像素比都是 1 的話,那麼能夠獲得它們的邏輯寬度分別是 320px 和 640px,從上面加了 viewport 屬性的例子來看的話,在 iphone 3 中藍色塊的寬度佔比是 100/320,而在 iphone 4 中佔比是 100/640,咱們就會看到一樣的代碼在不一樣的移動設備中的顯示差異很大。
而實際上 iphone 3 的設備像素比是 1,iphone 4 的設備像素比是 2,因此咱們能夠獲得它們的邏輯寬度都是 320px,因此實際上藍色塊在這兩款不一樣的移動設備中顯示的大小是同樣的。
因此咱們能夠得出,使用 px 像素單位時,一樣樣式的代碼在不一樣屏幕分辨率的移動設備中顯示的狀況基本一致(注意這裏是基本一致而不是徹底一致),是由於移動設備中的設備像素比將設備獨立像素轉換了。
而爲何說在不一樣分辨率的移動設備中顯示的狀況基本一致而不會徹底一致呢?是由於存在不少不一樣屏幕分辨率的移動設備,它們的邏輯寬度並不都是同樣的。
如 iphone 6 的分辨率是 1334 * 750,設備像素比是 2,因此其邏輯寬度是 375px,從上面加了 viewport 屬性的例子來看的話,藍色塊佔比是 100/375,能夠看到其藍色塊在屏幕中的佔比跟 iphone 三、iphone 4 是不同的。
因此咱們能夠知道,設備像素比在必定程度上幫助咱們進行了移動端適配。實際上,咱們還須要經過一些其它方案來對移動端進行適配。咱們須要進行移動端適配的根本緣由是存在多種不一樣邏輯寬度的移動設備
咱們對移動端進行適配的一個終極目標就是,使其在不一樣移動設備中所佔的比例是大體相同(對於上圖例子來講,就是使藍色塊在不一樣的移動設備中所佔的比例差很少)。
最後,是探究移動端適配的解決方案,這裏我要爲 《從網易與淘寶的font-size思考前端設計稿與工做流》 這篇博文打 call,寫得真的很不錯。在這篇博文中,分別介紹了拉勾、網易和淘寶的移動端適配解決方案,拉勾是經過設置樣式的百分比來達到在必定程度上對不一樣分辨率的移動設備進行適配,這種方式適合簡單項目的適配;而網易和淘寶使用的則是衆所周知的方案,使用 rem 進行適配。
相對而言,我以爲網易的方案更加容易理解和實踐,因此在個人項目中也是參考網易的方案來實現移動端適配的。而對於淘寶的移動端適配方案,則顯得更加精巧,感興趣的童鞋能夠自行閱讀理解哦。
那麼,rem 是什麼呢?rem(font size of the root element),意思即根據根元素的 font-size 來設置字體的大小。跟 px 同樣,它是 CSS 中的一個樣式單位,會根據根元素的 font-size 值來轉換成 px 單位,公式爲:px = rem * html(font-size)。
html{
font-size:10px;
}
div{
width:2rem; // 2*10=20px
}
複製代碼
因此咱們實現移動端適配的核心思想就是:使用 rem 做爲樣式單位,根據不一樣分辨率的移動設備設置根元素的 font-size 值。
那麼問題來了,如何合理地設置根元素的 font-size 值呢?
以 iphone 6 的設計稿爲基準,即設計稿橫向分辨率爲 750,取 100 爲參照數(即在使用 rem 時與使用 px 時相差 100 的倍數),則咱們能夠知道 html 的寬度爲 7.5rem(750 / 100),而咱們知道 iphone 6 的邏輯寬度是 375px,因此 html 的寬度也爲 375px,那麼此時 7.5rem * html(font-size) = 375px,因此能夠得出 html(font-size) = 375 / 7.5,即 html(font-size) = deviceWidth / 7.5。
經過 js 來設置根元素的 font-size
var deviceWidth = document.documentElement.clientWidth;
document.documentElement.style.fontSize = deviceWidth / 7.5 + 'px';
複製代碼
固然,這裏有一個前提,就是設置 viewprot 寬度爲移動設備的邏輯寬度
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
複製代碼
而當 deviceWidth 大於 750px 時,咱們應該去訪問的是 pc 版的頁面,因此當 deviceWidth 大於 750px 時咱們不該該再改變根元素的 font-size 值,完整的代碼以下
var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 750) deviceWidth = 750;
document.documentElement.style.fontSize = deviceWidth / 7.5 + 'px';
複製代碼
而爲了使咱們在書寫樣式的時候跟設計稿的大小更加契合,能夠經過 sass 的 function 來設置一個 px 與 rem 之間的轉換函數
@function pxToRem($num) {
@return ($num/100) * 1rem;
}
複製代碼
當設計稿中有一個寬高都爲 100px 的元素時,咱們即可以以下寫樣式
div{
width:pxToRem(100);
height:pxToRem(100);
}
複製代碼
還須要注意的是爲了使字體在不一樣分辨率的移動設備中看起來更加溫馨,其大小不該該用 rem,而應該使用 px。
最後,總結一下我在項目中使用的移動端適配方案:
不定時分享我的在前端方面的學習經驗,以爲還不錯的小夥伴,能夠關注一波公衆號哦。