flexiable.js
實現動態計算根元素 html
的 fontSize
值,以保證明際設備視口尺寸 (與meta[name="viewport"]標籤密切相)
永遠等於10rem
。flexiable.js
動態設置 meta[name="viewport"]
標籤,根據dpr進行scale值的設置(scale值直接會影響視口的實際尺寸,即設備尺寸/scale ===視口的實際尺寸 )
場景以下: 視覺稿:750*1334(2倍)
適配引入: flexiable.js + px2rem-loader
div尺寸:600px
css
iphone6/7/8 375*667 [window.devicePixelRatio === 2] =>
dpr === 2
=>
scale === 1/dpr === 1/2 === 0.5
=>
頁面插入 <meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
=>
根元素fontSize === (實際設備尺寸/viewport[scale] === 375/0.5 === 750) / 10 === 75px
=>
600px
通過px2rem-loader 處理,600 /75 === 8rem
。其中 75 爲按照實際視覺稿的尺寸計算的1rem對應的值,即 750/10
即此時div尺寸爲8rem,永遠是相對與根元素的尺寸進行等比例縮放,從而實現自適應尺寸佈局。即此時8rem實際的尺寸爲 8*75 === 600px 此時設備寬度爲375px,可是此時meta[name="viewport"] scale 爲 0.5,故實際600px對應的設備寬度僅爲300px(600px*0.5)
。自適應完成
✅html
iphone6/7/8 Plus 414*736 [window.devicePixelRatio === 3] =>
dpr === 3
=>
scale === 1/dpr === 1/3 === 0.3333333333
=>
頁面插入 <meta name="viewport" content="initial-scale=0.3333333333, maximum-scale=0.3333333333, minimum-scale=0.3333333333, user-scalable=no">
=>
根元素fontSize === (實際設備尺寸/viewport[scale] === 414/0.3333333333 === 1242) / 10 === 124.2px
=>
600px
通過px2rem-loader 處理,600 /75 === 8rem
。其中 75 爲按照實際視覺稿的尺寸計算的1rem對應的值,即 750/10
即此時div尺寸爲8rem,永遠是相對與根元素的尺寸進行等比例縮放,從而實現自適應尺寸佈局。即此時8rem實際的尺寸爲 8*124.2 === 993.6px 此時設備寬度爲414px,可是此時meta[name="viewport"] scale 爲 0.3333333333,故實際600px對應的設備寬度僅爲331.2px(993.6px*0.3333333333)
。自適應完成
✅react
綜上所述:設計稿的600px iphone6/7/8 375*667 dpr = 2
實際看到的爲 300px
iphone6/7/8 Plus 414*736 dpr = 3
實際看到的爲 331.2px
實際根據rem與根元素的比例關係進行適配webpack
// [flexiable.js](<https://github.com/posuihushui/flexible.js>)
//建立meta標籤,設置初始比、最小比和最大比均爲scale值,並將其插入到頁面
//設置了縮放比,那麼至關於這個屏幕渲染在一個被放大的畫布之上。
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {//並無什麼做用
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
// 自定義頁面元素的fontsize,方便rem的配置
function refreshRem(){
var docEl = window.document.documentElement;
// 重點:經過getBoundingClientRect()獲取的是實際渲染的畫布尺寸;(與meta[name="viewport"]標籤密切相關)
// 即:若是設置initial-scale爲0.5,deviceWidth(iphone6s)爲375,則width = 375 / 0.5 = 750
// 即:若是設置initial-scale爲0.3,deviceWidth(iphone6s)爲375,則width = 375 / 0.3 = 1250
var width = docEl.getBoundingClientRect().width;
// 限制最大fontSize爲64px
if (width / dpr > 640) {
width = 640 * dpr;
}
// 永遠保證:實際設備視口寬度(與meta[name="viewport"]標籤密切相關) === 10rem
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
// 監聽[resize|pageshow]觸發更新設置根元素fontSize值
window.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
window.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
複製代碼
// 經過使用react-app-rewired和customize-cra對默認webpack自定義添加px2rem-loader配置
// 參考源碼 [customize-cra/src/customizers/webpack.js](<https://github.com/arackaf/customize-cra/blob/master/src/customizers/webpack.js>)
// 參考配置 [px2rem-loader配置](<https://github.com/Jinjiang/px2rem-loader>)
const { override } = require("customize-cra");
const addPx2remLoader = (options) => (config) => {
// 獲取config全部loaders配置
const loaders = config.module.rules.find((rule) =>
Array.isArray(rule.oneOf)
).oneOf;
// 獲取針對/\.css$/文件的loader配置
const cssLoader = loaders.find((rule) => {
return rule.test && rule.test.toString() === "/\\.css$/";
});
// 追加px2rem-loader預處理loader
cssLoader.use = [
...cssLoader.use,
{
loader: "px2rem-loader",
// 採用參數傳遞px2rem-loader相關配置項
options,
},
];
return config;
};
module.exports = override(
addPx2remLoader({
remUnit: 75,
remPrecision: 8,
})
);
複製代碼
下面分別附上flexiable.js和px2rem的源碼地址(一、3): GitHub - posuihushui/flexible.js: 手機淘寶flexible.js解讀git
webpack配置相關:customize-cra/webpack.js at master · arackaf/customize-cragithub
GitHub - Jinjiang/px2rem-loader: Webpack loader for px2rem css fileweb