rem布局在Androidwebview中頁面錯亂


你有沒有遇到過如下這種問題(頁面錯亂):查看代碼,html的font-size設置正常,在瀏覽器和絕大部分手機上也正常,但是在某些手機上頁面元素為什么就大了或小了呢?是rem布局不准了嗎?

非也,其實是系統字體大小的問題,這類問題常見於安卓設備上,而且是內嵌在APP里面的H5頁面。

 

問題因素
出現這個問題有幾個因素:
1.用rem布局的H5頁面
2.頁面內嵌在APP的webview中
3.手機 設置 修改了默認字體大小,如下圖我的小米手機示例。

滿足以上三個因素,在很多手機上都會出現這個問題。

 

解決方案
方案一(獲取系統字體大小)
一般設計稿750px,為了便於計算,我們設1rem = 100px;也就是1rem = 1 * htmlFontSize (htmlFontSize 為 html 元素的字體大小),當然在iPhone6 375px寬的屏幕上,htmlFontSize 為50px。

其實,htmlFontSize 除了以px為單位外,還可以用百分比作為單位,比如你可以設置htmlFontSize的大小為312.5%,頁面的布局效果與設置htmlFontSize 大小為50px是一樣的效果。

那么問題來了,設置為百分比單位的時候,這個百分比值是怎么計算出來的呢?

瀏覽器默認字體大小為 16px,當我們使用百分比作為根節點 html 的字體大小時,rem 的計算方式就會改為

defaultFontSize = 16px
1rem = 1 * htmlFontSize * defaultFontSize
比如375像素寬設備上:

1rem = 1 * 312.5% *16 = 50 px
這與我們的實際情況相符,但是在有些 Android 手機上,瀏覽器或 webview 的默認字體是隨着系統設置的字體改變的。這樣就會導致默認字體大於或小於 16px。從這個思路出發,我們只需要找到系統設置的字體大小就可以正確的計算htmlFontSize的值了。

於是寫一個函數來獲取defaultFontSize的值:

//獲取系統默認字體大小
//designWidth 設計稿的寬度
//rem2px 設計稿寬度下,1rem的寬度
function adapt(designWidth, rem2px){
var d = window.document.createElement('div');
d.style.width = '1rem';
d.style.display = "none";
var head = window.document.getElementsByTagName('head')[0];
head.appendChild(d);
var defaultFontSize = parseFloat(window.getComputedStyle(d, null).getPropertyValue('width'));
return defaultFontSize
};

然后再結合我們之前計算 htmlFontSize 的函數可以得到完整的計算方式:

!(function(doc, win, designWidth, rem2px) {
var docEl = doc.documentElement,
defaultFontSize = adapt(designWidth, rem2px),
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function() {
var clientWidth = win.innerWidth
|| doc.documentElement.clientWidth
|| doc.body.clientWidth;

if (!clientWidth) return;
if (clientWidth < 750) {
docEl.style.fontSize = clientWidth / designWidth * rem2px / defaultFontSize * 100 + '%';

} else {
docEl.style.fontSize = '625%';
}
};
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);

})(document, window, 750, 100);

親測有效,看官可以回去一試!

方案二(獲取html元素實際寬度)
之前搜索了很久,也沒有看到很好的解決方案,包括像淘寶的flexible適配方案也沒有解決這個問題,今天寫文章的時候在搜索結果的后面幾頁,有一篇文章同樣也是介紹這個問題的,解決思路還是有點不太一樣的,這位同學是直接去獲取html的實際大小和理想值的比值,然后做 htmlFontSize 的相應處理,這里一並給大家分享!

一般,我們動態計算好html的font-size之后,我們就啥都不干了,就走了。但是,我們現在知道了,我們設置的大小不一定是真實的大小,所以,我們需要在設置完字體大小之后,再去重新獲取一下html的font-size,看看實際的這個值,和我們設置的是不是一樣。如果不一樣,就要根據比例再設置一次。

function htmlFontSize(){
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var width = w > h ? h : w;
width = width > 720 ? 720 : width
var fz = ~~(width*100000/36)/10000
document.getElementsByTagName("html")[0].style.cssText = 'font-size: ' + fz +"px";
var realfz = ~~(+window.getComputedStyle(document.getElementsByTagName("html")[0]).fontSize.replace('px','')*10000)/10000
if (fz !== realfz) {
document.getElementsByTagName("html")[0].style.cssText = 'font-size: ' + fz * (fz / realfz) +"px";
}
}
方案三(客戶端固定webview字體大小)
推動移動端同學進行處理,在APP內直接設置webview的默認字體大小。
如:在每個webview配置webview.getSettings().setTextZoom(100)就可以了。

同樣處理方式的有如微信,大家可以先修改下手機系統字體大小,然后再去體驗微信里面的游戲/購物(這里是用web實現的),發現根本不會受影響(首先我查看源碼看了下里面的頁面,是用了rem布局的)。

其實我建議用第三種方案進行處理,因為這樣體驗更統一,但是想想,如果用戶確實有調大字體的需求,或者有看小字體的習慣,用戶設置字體大小,你就是不給人家任何變化,也是相當不好的體驗呢。

所以微信就在 設置-通用-字體大小里面內置了設置字體大小的功能,幫助用戶得到更好的閱讀體驗。

當然你在微信里面調整了字體大小再去看 游戲/購物 發現還是沒有變化,這里就不清楚微信是直接固定了系統字體大小還是通過js處理rem布局頁面的,如果有微信的同學能看到的話,有興趣可以回答一下,謝謝!

 

擴展補充
擴展
微信的 iOS 版的調整字體大小使用的是通過給 body 設置 -webkit-text-size-adjust:120% 屬性實現的,Android 則是通過 Java 調用 webview 的 API 設置字體大小。

補充
如果是用方案一,而且要繼續解決 rem布局加載閃爍問題,那么就要將原來的媒體查詢全部換成百分比單位的,代碼如下:

@media (min-width: 320px){html{font-size: 266.667%;} }
@media (min-width: 360px){html{font-size: 300%;} }
@media (min-width: 375px){html{font-size: 312.5%;;} }
@media (min-width: 384px){html{font-size: 320%;} }
@media (min-width: 414px){html{font-size: 345%;} }
@media (min-width: 448px){html{font-size: 373.333%;} }
@media (min-width: 480px){html{font-size: 400%;} }
@media (min-width: 512px){html{font-size: 426.667%;} }
@media (min-width: 544px){html{font-size: 453.333%;} }
@media (min-width: 576px){html{font-size: 480%;} }
@media (min-width: 608px){html{font-size: 506.667%;} }
@media (min-width: 640px){html{font-size: 533.333%;} }
@media (min-width: 750px){html{font-size: 625%;;} }
但是,非常嚴重的問題。引入文件時,方案一計算的js文件必須要放在媒體查詢的css文件前面,不然就會出現 htmlFontSize 一直都是100%的計算錯誤,這個問題目前我還沒有找到其他解決方案,只能先放在前面了。(腳本就十幾行,放在前面對DOM的渲染影響也不大)

更新1024
看這篇文章的文末反思部分 rem布局加載閃爍問題。

1.html{font-size: 50px;}//這個一定寫
2.JS動態計算和密集的媒體查詢二選一

基於此和解決rem布局在webview中頁面錯亂問題,我們如果是選擇JS動態計算,因計算的原理需要,我們要將JS(或JS引入)放在CSS(或者CSS引入)之前。媒體查詢方案沒有要求。
---------------------
 
原文:https://blog.csdn.net/u013778905/article/details/77972841


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM