在 Viewport 等比適配始末 說過使用 Viewport 來實現等比適配的例子,本文詳解等比適配的另外一種方式javascript
拿到一個寬度爲 vWidth 的視覺稿
設設備屏幕寬度爲 dWidth
在視覺稿上量得一個元素的寬度爲 eleVWidth
那麼要實現按照寬度等比適配,在各類設備中元素的實際寬度 x 將知足公式css
//等比
eleVWidth/vWidth = X/dWidth;
//咱們的目的是求X
X = (eleVWidth/vWidth)dWidth;複製代碼
拿到視覺稿以後,eleVWidth 和 vWidth 都已經固定了,可是 dWidth 在不一樣的設備中確實不一樣的,並且須要實際運行的時候咱們才能拿到 dWidth,這個時候就要利用 rem 的特性了,咱們經過阻塞運行的 js 動態設置 rem,使得rem=dWdith/10
,套入剛纔的公式:html
X=(eleVWidth/vWidth)*10*rem
//體如今css中
.className {
width: (eleVWidth/vWidth)*10 rem
}複製代碼
爲何設置是 dWdith/10 呢?方便計算而已,固然也能夠除以別的基數,可是儘可能不要讓 rem 過小,有兼容性問題java
這段 css 須要放在 body 標籤的開始位置,由於 rem 值要儘量早的設置成功,避免無謂的重排重繪(有些設備中若元素樣式已經生效,動態改變 rem 未必能起做用,因此這個動做更須要提早)android
<body>
<script> (function() { var ua = window.navigator.userAgent; var docEl = document.documentElement; var html = document.querySelector('html'); var isAndorid = /Android/i.test(ua); var dpr = window.devicePixelRatio || 1; var rem = docEl.clientWidth / 10; // 設置 rem 基準值 html.style.fontSize = rem + 'px'; // Nexus 5 上 rem 值不許, // 如:設置100px,getComputedStyle 中的值卻爲 85px,致使頁面錯亂 // 這時須要檢查設置的值和計算後的值是否同樣, // 不同的話從新設置正確的值 var getCPTStyle = window.getComputedStyle; var fontSize = parseFloat(html.style.fontSize, 10); var computedFontSize = parseFloat(getCPTStyle(html)['font-size'], 10); if (getCPTStyle && Math.abs(fontSize - computedFontSize) >= 1) { html.style.fontSize = fontSize * (fontSize / computedFontSize) + 'px'; } // 設置 data-dpr 屬性,留做的 css hack 之用 html.setAttribute('data-dpr', dpr); // 安卓平臺額外加上標記類 if (isAndorid) { html.setAttribute('data-platform', 'android'); } })(); </script>
...
</body>複製代碼
若是每在視覺稿上量出一個值,在寫到樣式文件以前都得經過那個公式計算一翻,那絕對不是一個好策略,咱們但願量到啥就寫啥webpack
使用 less,sass 等 css 預處理器的函數web
//設計稿爲640
@function rem($val) {
@return $val/64 * 1rem;;
}
//設計稿爲750
@function rem750($val) {
@return $val/75 * 1rem;
}
//使用
.className {
width: @rem(100);
}複製代碼
也可使用 webpack-loader,例如:change-rem-loader,這個 loader 代碼作的事也是上述的轉化計算(寫一個 webpack loader 並不複雜,你能夠本身寫一個符合本身狀況的 loader)npm
'use strict';
module.exports = function(source) {
source = source.replace(/rem(\d*)\((.*?)\)/g, function(match, type, value) {
var divVal;
// 不作 try catch,及早發現錯誤以避免形成故障
switch (type) {
// 1080寬度的設計稿,rem1080(value)
case '1080':
divVal = 108;
break;
// 默認爲750寬度的設計稿,rem(value)
case '750':
divVal = 75;
break;
default:
divVal = 64;
}
return (value / divVal).toFixed(6) + 'rem';
});
return source;
}複製代碼
這樣以後,咱們 css 一樣能夠這樣寫(如何讓 loader 起做用不是本文的範圍)sass
.className {
width: rem(100);
}複製代碼
也許你的工程技術棧裏面,使用的不是 webpack,也沒有使用 less、sass 等預處理器,那你能夠根據你的實際狀況去尋找一種預處理方案,只要達到推導公式的效果就能夠了。
什麼?沒有合適的方案,那你是時候充充電了less
期待您的關注~~