H5 android老人机适配方案

2018-04-12  本文已影响208人  风之化身呀

前言

部门移动端布局采用的是rem+font-size的方案,这种方案中font-size的值至关重要。正常情况下页面不会出现布局错乱现象,但是部分android机,通过改变系统默认字号(若改成大号字体)会导致font-size值被放大,相当于乘了一个放大因子scale,从而导致页面布局错乱,本文就是解决这个问题。
(所谓老人机,这里指手动修改了系统默认字体或缩放设置)

举例

数据来源:三星S8手机

系统缩放设置 系统字体设置 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

结论:
1、系统缩放设置(部分手机能设置该项)可改变clientWidth(取自document.documentElement.clientWidth);
2、同缩放下,系统默认字体被修改后,虽然font-size值没变,但在渲染时实际上被隐式放大或缩小了,记为缩放因子scale;

方案

思路:这个缩放因子scale很重要,它是导致页面布局错乱的罪魁祸首,如果知道这个scale,那么取其倒数,就可以恢复正常。
先看看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>

由上表可知,缩放程度为中,默认字体为小时,页面正常显示。现在考虑缩放程度为中,默认字体为中的情形:
字面上计算的font-size没变(记为F1),但实际上渲染时的font-size是被放大了的,记为(F1=F2*scale),得出scale=F1/F2;
关键点:scale还可以这么计算,正常情况下,我们认为页面宽度被分为7.5份,但缩放后页面肯定不是7.5份了,假设缩放后页面宽度被分为N份,则scale*N=7.5,得scale=7.5/N;所以有7.5/N=F1/F2,从而有F2=F1*N/7.5;只要计算出N,就能计算出F2。
下面就是如何计算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后,设置为html的font-size=F2即可修复该问题。
完整代码:

 (function() {
        var maxLimitW = 768,
            remCount = 7.5,
            clientW = document.documentElement.clientWidth,
            hasReadyInit;
        // 兼容三星S8 bug,只有第一次进入时才能取得clientW的值,第二次进该值为0,所以用localStorage存起来
        if (clientW) {
            localStorage.setItem('clientW', clientW);
        } else {
            clientW = localStorage.getItem('clientW');
        }
        var initFontSize = Math.min(maxLimitW, clientW) / remCount;
        document.documentElement.style.fontSize = initFontSize + 'px';
        // 修正系统设置了字号之后,支持动态字体的APP会强制调整网页font-size,导致rem方式的适配乱版问题(比如下面ua)
        //eg. 华为QQ内置浏览器 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; //已经注册过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)
        });
    })();
上一篇下一篇

猜你喜欢

热点阅读