前言
部門(mén)移動(dòng)端布局采用的是rem+font-size的方案,這種方案中font-size的值至關(guān)重要滔金。正常情況下頁(yè)面不會(huì)出現(xiàn)布局錯(cuò)亂現(xiàn)象圈澈,但是部分android機(jī),通過(guò)改變系統(tǒng)默認(rèn)字號(hào)(若改成大號(hào)字體)會(huì)導(dǎo)致font-size值被放大按价,相當(dāng)于乘了一個(gè)放大因子scale惭适,從而導(dǎo)致頁(yè)面布局錯(cuò)亂,本文就是解決這個(gè)問(wèn)題楼镐。
(所謂老人機(jī)癞志,這里指手動(dòng)修改了系統(tǒng)默認(rèn)字體或縮放設(shè)置)
舉例
數(shù)據(jù)來(lái)源:三星S8手機(jī)
系統(tǒng)縮放設(shè)置 | 系統(tǒng)字體設(shè)置 | clientWidth | font-size(clientWidth/7.5) | 布局是否正常 |
---|---|---|---|---|
小 | 小 | 412 | 54.93 | 否 |
小 | 中 | 412 | 54.93 | 否 |
小 | 大 | 412 | 54.93 | 否 |
中 | 小 | 360 | 48 | 是 |
中 | 中 | 360 | 48 | 否 |
中 | 大 | 360 | 48 | 否 |
大 | 小 | 320 | 42.67 | 否 |
大 | 中 | 320 | 42.67 | 否 |
中 | 大 | 320 | 42.67 | 否 |
結(jié)論:
1、系統(tǒng)縮放設(shè)置(部分手機(jī)能設(shè)置該項(xiàng))可改變clientWidth(取自document.documentElement.clientWidth)框产;
2凄杯、同縮放下,系統(tǒng)默認(rèn)字體被修改后茅信,雖然font-size值沒(méi)變盾舌,但在渲染時(shí)實(shí)際上被隱式放大或縮小了,記為縮放因子scale蘸鲸;
方案
思路:這個(gè)縮放因子scale很重要妖谴,它是導(dǎo)致頁(yè)面布局錯(cuò)亂的罪魁禍?zhǔn)祝绻肋@個(gè)scale酌摇,那么取其倒數(shù)膝舅,就可以恢復(fù)正常。
先看看rem+font-size的布局套路:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<title>墨粉club</title>
<script>
(function() {
var maxLimitW = 768,
remCount = 7.5,
clientW = document.documentElement.clientWidth||document.body.clientWidth;
var initFontSize = Math.min(maxLimitW, clientW) / remCount;
document.documentElement.style.fontSize = initFontSize + 'px';
})();
</script>
</head>
由上表可知窑多,縮放程度為中仍稀,默認(rèn)字體為小時(shí),頁(yè)面正常顯示」∠ⅲ現(xiàn)在考慮縮放程度為中技潘,默認(rèn)字體為中的情形:
字面上計(jì)算的font-size沒(méi)變(記為F1),但實(shí)際上渲染時(shí)的font-size是被放大了的千康,記為(F1=F2*scale)享幽,得出scale=F1/F2;
關(guān)鍵點(diǎn):scale還可以這么計(jì)算,正常情況下拾弃,我們認(rèn)為頁(yè)面寬度被分為7.5份值桩,但縮放后頁(yè)面肯定不是7.5份了,假設(shè)縮放后頁(yè)面寬度被分為N份豪椿,則scale*N=7.5奔坟,得scale=7.5/N携栋;所以有7.5/N=F1/F2,從而有F2=F1*N/7.5咳秉;只要計(jì)算出N婉支,就能計(jì)算出F2。
下面就是如何計(jì)算N:
document.addEventListener('DOMContentLoaded', function() {
var remFixDom = document.createElement("div");
remFixDom.style.cssText = "width:100%;height:1rem;opacity:0;position:absolute;z-index:-9999;";
document.body.appendChild(remFixDom);
var render = window.getComputedStyle(remFixDom);
var N = (render.width.slice(0, -2) / render.height.slice(0, -2)).toFixed(1);
setTimeout(function() {
remFixDom.style.cssText = "height:0";
}, 1000)
});
算出F2后滴某,設(shè)置為html的font-size=F2即可修復(fù)該問(wèn)題磅摹。
完整代碼:
(function() {
var maxLimitW = 768,
remCount = 7.5,
clientW = document.documentElement.clientWidth,
hasReadyInit;
// 兼容三星S8 bug,只有第一次進(jìn)入時(shí)才能取得clientW的值霎奢,第二次進(jìn)該值為0户誓,所以用localStorage存起來(lái)
if (clientW) {
localStorage.setItem('clientW', clientW);
} else {
clientW = localStorage.getItem('clientW');
}
var initFontSize = Math.min(maxLimitW, clientW) / remCount;
document.documentElement.style.fontSize = initFontSize + 'px';
// 修正系統(tǒng)設(shè)置了字號(hào)之后,支持動(dòng)態(tài)字體的APP會(huì)強(qiáng)制調(diào)整網(wǎng)頁(yè)font-size幕侠,導(dǎo)致rem方式的適配亂版問(wèn)題(比如下面ua)
//eg. 華為QQ內(nèi)置瀏覽器 Android 7.0; EVA-AL00 Build/HUAWEIEVA-AL00; wv) Mobile MQQBrowser/6.2 QQ/7.1.5.3215
if (clientW >= maxLimitW) return;
if (hasReadyInit) return; //已經(jīng)注冊(cè)過(guò)ready修正事件了
document.addEventListener('DOMContentLoaded', function() {
var remFixDom = document.createElement("div");
remFixDom.style.cssText = "width:100%;height:1rem;opacity:0;position:absolute;z-index:-9999;";
document.body.appendChild(remFixDom);
var render = window.getComputedStyle(remFixDom);
var rRate = (render.width.slice(0, -2) / render.height.slice(0, -2)).toFixed(1);
var finalFontSize = initFontSize * (rRate / remCount);
if (finalFontSize) {
localStorage.setItem('finalFontSize', finalFontSize);
} else {
finalFontSize = localStorage.getItem('finalFontSize');
}
if (rRate != remCount) document.documentElement.style.fontSize = finalFontSize + "px";
hasReadyInit = true;
setTimeout(function() {
remFixDom.style.cssText = "height:0";
}, 1000)
});
})();