背景介紹
目前,隨着移動設備的普及和4G網絡的普及,web在移動端的占比已經遠遠超過PC端,各種H5頁面推廣頁面,H5小游戲熱度火爆。以前簡單的使用px單位(沒有彈性)的時代已經無法滿足各位設計師和用戶了。如何100%還原UI設計師的設計圖,一直困擾着前端工程師。
css單位
學習首先我們簡單了解下css目前都支持哪些單位:
- px: 設置固定的布局或者元素大小,缺點是沒有彈性
- em: 參考父元素的font-size,em會繼承父級元素的字體大小,em的值並不是固定的
- rem: 相對根元素html的font-size
- %: 相對父元素,對於position: absolute;的元素是相對於已定位的父元素,對於position: fixed;的元素是相對於ViewPort(可視窗口)
- vw: view width的簡寫, 是指可視窗口的寬度,瀏覽器寬度1200px, 1 vw = 1200px/100 = 12 px
- vh: view height的簡寫,是指可視窗口的高度,瀏覽器高度900px, 1 vh = 900px/100 = 9 px
- vm: 相對於視口的寬度或高度中較小的那個, 其中最小的那個被均分為100單位的vm,瀏覽器高度900px,寬度1200px,取最小的瀏覽器高度,1 vm = 900px/100 = 9 px
- in: 寸
- cm: 厘米
- mm: 毫米
- pt: point, 大約1/72寸
- pc: pica, 大約6pt, 1/6寸
具有彈性布局能力的單位:
- em,%: 相對於父元素
- rem: 相對於html
- vw, vh, vm: 相對於可視窗口
從上可以看出,要做頁面整體彈窗縮放的話,使用rem, vm, vw, vh更適合,因為任何內容都可以找到同一個基准。
HTML viewport基礎
概念
viewport 是用戶網頁的可視區域。
手機瀏覽器是把頁面放在一個虛擬的"窗口"(viewport)中,通常這個虛擬的"窗口"(viewport)比屏幕寬,這樣就不用把每個網頁擠到很小的窗口中(這樣會破壞沒有針對手機瀏覽器優化的網頁的布局),用戶可以通過平移和縮放來看網頁的不同部分。
用法
<meta name="viewport" content="width=device-width, initial-scale=1.0">
屬性說明
- width:控制 viewport 的大小,可以指定的一個值,如 600,或者特殊的值,如 device-width 為設備的寬度(單位為縮放為 100% 時的 CSS 的像素)。
- height:和 width 相對應,指定高度。
- initial-scale:初始縮放比例,也即是當頁面第一次 load 的時候縮放比例,默認值1。
- maximum-scale:允許用戶縮放到的最大比例。
- minimum-scale:允許用戶縮放到的最小比例。
- user-scalable:用戶是否可以手動縮放。
彈性布局方案
通過以上可以看出,使用彈性布局的css單位配合設置html viewport元信息,就可以實現整體頁面的彈性布局(包含字體大小)。
先弄明白幾個概念:
設備分辨率:一個物理像素是顯示器(手機屏幕)上最小的物理顯示單元,在操作系統的調度下,每一個設備像素都有自己的顏色值和亮度值;
設備屏幕寬度:設備顯示器的實際寬度;
DPR:設備上物理像素和設備獨立像素(device-independent pixels (dips))的比例,DPR = 設備分辨率/設備屏幕寬度;
300ppi:每英寸300個像素點
思路
根據以上的概念,那么,我們知道
window.devicePixelRatio = document.body.clientWidth / window.screen.width;
如果屏幕分辨率寬是1080px,屏幕寬度為360px,那么DPR=1080/360=3。
如果現在UI設計圖也是1080px,那么前端工程師不想丟失任何細節的使用代碼如何還原呢?
可以設置屏幕寬度為1080px, 設置viewport屬性initial-scale = 1/3;
這樣360px的屏幕就可以容納1080px寬的內容了。
但是每個手機的分辨率都不一樣,那么如何來設置這個這個initial-scale呢?我們可以通過以下方式:
var scale = 1 / window.devicePixelRatio; document.querySelector('meta[name="viewport"]').setAttribute('content', 'user-scalable=no,initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale);
將user-scalable設置為no, 不允許縮放,有縮放需要的,可以不設置
之后如何設置某一個區塊的寬,高,或者字體大小呢?
我們還需要設置html標簽,字體的大小,我習慣於使用設計圖的寬/20來獲取元素的rem數值。比如
- UI設計圖文字大小30px, 那么我習慣使用 font-size: 1.5rem;
- UI設計圖圖片寬100px, 我習慣使用 width: 5rem;
那么我會設置html的font-size為 deviceWidht / (UI設計圖寬/20);
var base = 720 / 20; // 720為UI設計稿的寬 var fontSize = deviceWidth / base; document.documentElement.style.fontSize = fontSize + 'px';
結合以上,完整代碼為:
<script type="text/javascript"> var scale = 1 / window.devicePixelRatio; document.querySelector('meta[name="viewport"]').setAttribute('content', 'user-scalable=no,initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale); window.onresize = function (base) { var deviceWidth = (document.body.clientWidth < document.documentElement.clientWidth) ? document.body.clientWidth : document.documentElement.clientWidth; var screenWidth = window.screen.width; if (deviceWidth / screenWidth != window.devicePixelRatio) { document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'); deviceWidth = (document.body.clientWidth < document.documentElement.clientWidth) ? document.body.clientWidth : document.documentElement.clientWidth; } var fontSize = deviceWidth / base; document.documentElement.style.fontSize = fontSize + 'px'; }; window.onresize(720); </script>
以上代碼我放在<head>里面,在html標簽渲染前就開始設置。
一開始就根據DPR設置initial-scale,之后在onresize里面設置html字體大小。
大家會注意到onresize里面有這樣一段代碼:
var deviceWidth = (document.body.clientWidth < document.documentElement.clientWidth) ? document.body.clientWidth : document.documentElement.clientWidth; var screenWidth = window.screen.width; if (deviceWidth / screenWidth != window.devicePixelRatio) { document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'); deviceWidth = (document.body.clientWidth < document.documentElement.clientWidth) ? document.body.clientWidth : document.documentElement.clientWidth; }
這一段代碼是為了兼容一部分舊款機器,這些機器無法正常的獲取到DPR值,那么我們就只能設置屏幕頁面內容寬度為設備寬度。
有疑問,歡迎聯系博主討論。