在前一段時間,我曾經寫過一篇關於viewport的文章。最近因爲在接觸移動端開發,對viewport有了新的理解。因而,打算從新寫一篇文章,介紹移動端視口的相關概念。前端
關於這篇文章說到的全部知識,本質上離不開如下代碼web
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> @media all and (max-width: 320px) { // do something }
瞭解過移動端開發的朋友,其實對以上的代碼就不會陌生。上面的代碼,主要涉及到meta視口標籤與媒體查詢。單單以上簡短的代碼就須要明白:瀏覽器
那就進入主題吧:)app
在移動端上,所謂的像素分爲兩種ide
1個CSS像素等於多少個設備像素取決於屏幕特性(是不是高清屏)和用戶縮放的比例。當用戶將屏幕從100%放大到200%時,1個CSS像素等於2個設備像素,反之相反;當屏幕爲Retina高清屏(如iPhone6,dpr=2)時,1個CSS像素就等於2個設備像素,反之相反。佈局
須要明白一點的是,2個設備像素並非說它擴大了兩倍,而是說在頁面上仍然顯示的是1px(1個CSS像素),可是這1px是由2個設備像素組成。像素點變多了,所以圖像會變得更加清晰。下面這幅圖大體說明了CSS像素和設備像素的區別。
字體
在移動端上,存在三種不一樣的視口。網站
document.documentElement.clientWidth | document.body.clientWidth
獲得。在PC端上,視覺視口等於佈局視口的寬度,不管用戶是放大屏幕仍是縮小屏幕,這兩個視口的寬度仍然相等。可是,在移動端上,並不是如此。縮放屏幕的過程實質上就是CSS像素縮放的過程。當用戶將屏幕放到到兩倍時,視覺視口變小了(由於視覺視口中CSS像素變少了),而每單位的CSS像素卻變大了,所以1px(1個CSS像素)等於2個設備像素。同理,當爲iPhone6(dpr=2)時,視覺視口中CSS像素變少了,可是1px等於2個設備像素。當用戶縮小屏幕時也是一樣的道理。縮放的過程並不會影響佈局視口的大小。idea
也就是說,高清屏(dpr>=2)或屏幕放大時,視覺視口變小(CSS像素變少),每單位的CSS像素等於更多的設備像素;非高清屏(dpr<2)
或屏幕縮小時,視覺視口變大(CSS像素變多),每單位的CSS像素等於更少的設備像素。
可是不管放大或縮小屏幕,佈局視口的寬度仍然保持不變。scala
window.screen.width
獲得。<meta name="viewport" content="width=device-width" />
當設置了meta視口標籤以後,iPhone6的佈局視口寬度將等於375px,iPhone6plus佈局視口的寬度等於414px。其餘移動設備類似。
理想視口會隨着屏幕的旋轉而改變。當iPhone6爲肖像模式時(即豎屏),此時理想視口爲375px * 667px;但爲橫屏模式時,此時理想視口爲667px * 375px。
分辨率是指每英寸內點的個數,單位是dpi或者dppx。設備像素比是指設備像素與理想視口寬度的比值,沒有單位。
分辨率在CSS上能夠經過resolution
屬性設置。通常狀況下會使用dpi做爲分辨率的單位,由於dppx並不是全部瀏覽器都支持。
而設備像素比在CSS上能夠經過device-pixel-ratio
屬性設置,而在JavaScript上能夠經過window.devicePixelRatio
屬性獲取。
同時,1dpr=96dpi。舉個例子。在iPhon6下,理想視口寬度爲375px,而設備像素爲750px,所以此時設備像素比爲2,分辨率爲192dpi。所以若是爲iPhon6如下的設備寫某個特定樣式,能夠這樣寫
// 注意,device-pixel-ratio須要帶上-webkit-前綴,保證瀏覽器兼容性問題。 @media all and (max-width: 375px) and (-webkit-max-device-pixel-ratio: 2) { body { background-color: red; } } 或者 @media all and (max-width: 375px) and (max-resolution: 192dpi) { body { background-color: red; } }
meta視口標籤是是設置理想視口的重要元素,主要用於將佈局視口的尺寸和理想視口的尺寸相匹配。meta視口標籤存在5個指令
須要注意的是,縮放是根據理想視口進行計算的。縮放程度與視覺視口的寬度是逆相關的。也就是說,當你將屏幕放到到2倍時,視覺視口爲理想視口的一半,此時每單位的CSS像素等於2個設備像素。縮小時則相反。
理解了一些基本概念以後,咱們來看看如何實現響應式適配。
通常狀況下,前端開發工程師會根據設計師給的設計稿進行開發。而設計稿通常是根據iPhon6手機進行頁面的設計的。咱們知道iPhone6的理想視口寬度爲375px,同時iPhone6的設備像素比爲2,設備像素爲750px。咱們須要在只有一份設計稿的狀況下寫出適應各類屏幕不一的終端設備,所以須要一些移動端響應式適配的方案。此時須要用到的一個單位是REM
。簡單的說,REM會根據HTML元素的font-size
進行設置。當HTML元素的font-size: 16px
時,1rem = 16px, 1.5rem = 24px
我的總結出了兩套響應式適配的方案(前提是設置meta視口標籤)。兩套方案由一個共同點:給定一個基準值。
假如如今拿到的設計稿是根據iPhone6進行設計的。
方案一是設計稿給什麼尺寸,咱們就將其縮小100倍,最後換算成rem單位。好比,設計稿上某個title的font-size
爲32px,此時寫CSS樣式時就直接縮小100倍,即0.32rem
。
因爲rem是根據根元素進行設置的,因此咱們須要設置根元素的font-size
。
給HTML設置font-size
的基本思路:
window.screen.width
獲取不一樣移動設備的理想視口寬度。font-size
。(乘於100是由於咱們在前面將字體縮小了100倍,此時要乘回來)換算成公式即:設計稿尺寸 / 100 * (不一樣設備的理想視口寬度 / 基準值 * 100)
舉個例子。
// 根據不一樣設備的理想視口寬度動態設置根元素的`font-size`。 let idealViewWidth = window.screen.width; const BASICVALUE = 750; document.documentElement.style.fontSize = (idealViewWidth / BASICVALUE) * 100 + 'px';
所以,在不一樣設備下的HTML元素的font-size
大小和實際像素以下
iPhone5 : (320 / 750) * 100 = 42.667px iPhone6 : (375 / 750) * 100 = 50px iPhone6+: (414 / 750) * 100 = 55.2px 假如設計稿上標註.title類上的字體爲32px,此時有 iPhone5上的某字體: 42.667 * 0.32rem = 13.653px iPhone6上的某字體: 50 * 0.32rem = 16px iPhone6+上的某字體: 55.2 * 0.32rem = 17.664px
能夠看出,在不一樣設備下,同一字號的字體使用rem單位能夠實現不一樣設備的響應式適配。不僅僅在字體上可使用,在移動端上的width、height等涉及單位的均可以使用。這樣的話,就能夠在不一樣設備下完美的復現設計稿的要求。
此方案使用了SASS預處理器。基本思路:
font-size
。經過獲取不一樣設備的理想視口寬度,再除以10。(除以10是由於不想font-size
太大。)代碼以下
SASS @function px2rem ($value) { $para: 75px; @return $value / $para + rem; } JS let idealViewWidth = window.screen.width; document.documentElement.style.fontSize = idealViewWidth / 10 + 'px'; 在不一樣設備下根元素的`font-size`: iPhone5 : 320px / 10 = 32px iPhone6 : 375px / 10 = 37.5px iPhone6+: 414px / 10 = 41.4px 根據以上,能夠看一個例子。某設計稿下5個li,橫向排布,每一個的寬度爲200px CSS @import (路徑名) iPhone5: li { width: px2rem(200px) } => width: 85.333px // 此時(200px / 75px = 2.667rem) 2.667rem = 2.667 * (320 / 10) = 85.3333px iPhone6: li { width: px2rem(200px) } => width: 100px // 此時(200px / 75px = 2.667rem) 2.667rem = 2.667 * (375 / 10) = 100px iPhone6+: li { width: px2rem(200px) } => width: 4138px // 此時(200px / 75px = 2.667rem) 2.667rem = 2.667 * (414 / 10) = 110.4138px 所以,一個200px的(實際只有100px)的li元素的寬度在不一樣設備下顯示了不一樣的寬度,實現了響應式適配的問題。
方案三與前兩個方案不相同,此方案並不須要給根元素設置font-size
,不須要基準值。此方案是根據不一樣設備的dpr來實現頁面的縮放的。
基本思路以下:
代碼以下:
let dpr = window.devicePixelRatio; let meta = document.createElement('meta'); let initialScale = 1 / dpr; let maximumScale = 1 / dpr; let minimumScale = 1 / dpr; meta.setAttribute('name', 'viewport'); meta.setAttribute('content', `width=device-width, user-scalable=no, initial-scale=${initialScale}, maximum-scale=${maximumScale}, minimum-scale=${minimumScale}`); document.head.appendChild(meta); 所以,能夠直接根據設計稿的尺寸寫CSS樣式,如設計稿下有5個li元素,寬度爲200px,此時不一樣設備下li的寬度 iPhone5 : li { width: 200px } 實際寬度爲:100px iPhone6 : li { width: 200px } 實際寬度爲:100px iPhone6+: li { width: 200px } 實際寬度爲:66.667px
以上三種方法解決了大部分移動端響應式適配的問題,可是在1px問題上,使用以上的方法仍然(除了第三個方案),都不能很好的解決1px的問題。有時間寫一篇文章介紹如何解決1px的問題。
固然..關於移動端響應式適配還有許多好的解決方法,但願留言同你們分享:)