天天看點

rem布局在webview中頁面錯亂

上一篇我分享了 rem布局加載閃爍問題,這個問題也是在rem布局經常遇到而且還比較好解決的問題。

但是!注意,這裡但是哈!(一般但是都要搞事情)

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

非也,其實是系統字型大小的問題,這類問題常見于安卓裝置上,而且是内嵌在APP裡面的H5頁面。

rem布局在webview中頁面錯亂
rem布局在webview中頁面錯亂

問題因素

出現這個問題有幾個因素:

1.用rem布局的H5頁面

2.頁面内嵌在APP的webview中

3.手機 設定 修改了預設字型大小,如下圖我的小米手機示例。

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

rem布局在webview中頁面錯亂

解決方案

方案一(擷取系統字型大小)

一般設計稿750px,為了便于計算,我們設

1rem = 100px;

也就是

1rem = 1 * htmlFontSize

(htmlFontSize 為 html 元素的字型大小),當然在iPhone6 375px寬的螢幕上,htmlFontSize 為50px。

其實,htmlFontSize 除了以

px

為機關外,還可以用百分比作為機關,比如你可以設定htmlFontSize的大小為

312.5%

,頁面的布局效果與設定htmlFontSize 大小為

50px

是一樣的效果。

那麼問題來了,設定為百分比機關的時候,這個百分比值是怎麼計算出來的呢?

浏覽器預設字型大小為 16px,當我們使用百分比作為根節點

html

的字型大小時,rem 的計算方式就會改為

defaultFontSize = px
1rem =  * htmlFontSize * defaultFontSize
           

比如375像素寬裝置上:

這與我們的實際情況相符,但是在有些 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')[];
    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 < ) {
               docEl.style.fontSize = clientWidth / designWidth * rem2px / defaultFontSize *  + '%';

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

})(document, window, , );
           

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

方案二(擷取html元素實際寬度)

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

一般,我們動态計算好html的font-size之後,我們就啥都不幹了,就走了。但是,我們現在知道了,我們設定的大小不一定是真實的大小,是以,我們需要在設定完字型大小之後,再去重新擷取一下html的font-size,看看實際的這個值,和我們設定的是不是一樣。如果不一樣,就要根據比例再設定一次。
function htmlFontSize(){
    var h = Math.max(document.documentElement.clientHeight, window.innerHeight || );
    var w = Math.max(document.documentElement.clientWidth, window.innerWidth || );
    var width = w > h ? h : w;
    width = width >  ?  : width
    var fz = ~~(width*/)/
    document.getElementsByTagName("html")[].style.cssText = 'font-size: ' + fz +"px";
    var realfz = ~~(+window.getComputedStyle(document.getElementsByTagName("html")[]).fontSize.replace('px','')*)/
    if (fz !== realfz) {
        document.getElementsByTagName("html")[].style.cssText = 'font-size: ' + fz * (fz / realfz) +"px";
    }
}
           

方案三(用戶端固定webview字型大小)

推動移動端同學進行處理,在APP内直接設定webview的預設字型大小。

如:在每個webview配置webview.getSettings().setTextZoom(100)就可以了。

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

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

是以微信就在 設定-通用-字型大小裡面内置了設定字型大小的功能,幫助使用者得到更好的閱讀體驗。

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

rem布局在webview中頁面錯亂

擴充補充

擴充

微信的 iOS 版的調整字型大小使用的是通過給 body 設定 -webkit-text-size-adjust:120% 屬性實作的,Android 則是通過 Java 調用 webview 的 API 設定字型大小。

補充

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

@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;} }
@media (min-width: px){html{font-size: %;;} } 
           

但是,非常嚴重的問題。引入檔案時,方案一計算的js檔案必須要放在媒體查詢的css檔案前面,不然就會出現 htmlFontSize 一直都是100%的計算錯誤,這個問題目前我還沒有找到其他解決方案,隻能先放在前面了。(腳本就十幾行,放在前面對DOM的渲染影響也不大)

更新1024

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

1.html{font-size: 50px;}//這個一定寫

2.JS動态計算和密集的媒體查詢二選一

基于此和解決rem布局在webview中頁面錯亂問題,我們如果是選擇JS動态計算,因計算的原理需要,我們要将JS(或JS引入)放在CSS(或者CSS引入)之前。媒體查詢方案沒有要求。

參考來源:

https://github.com/hbxeagle/rem/blob/master/README.md

http://blog.csdn.net/fungleo/article/details/73309396

繼續閱讀