zoukankan      html  css  js  c++  java
  • 微信字体放大影响布局的处理

    下图中是安卓微信中调整字体大小后的效果,行内的font-size:12px !important设置没起作用,个人觉得是webview做了另外的处理,使用getComputedStyle获取到的字体也确实是变大了(而且这是全局的,对所以元素都生效,包括页面加载后append的元素),对设定了绝对值的元素则不影响。

    很多webview提供了调整页面字体大小的功能,例如手机QQ、微信、部分Android内置浏览器等。大部分浏览器调整字体只会导致字体显示大小发生改变,其他元素的大小不受影响。但对于结构稍微复杂一点的页面,字体大小的变动就足以导致页面布局乱掉,导致文本不居中、文字折行、布局混乱等问题。
    由于并不是很清楚各个平台(浏览器)放大字体的机制,我分别咨询了我们 iOS 和 Android 的同事,得知在调整字体大小时时,2个客户端的处理方式不同。

    iOS
    iOS上需要调整 webview 的字体大小时,是通过给 body 设置 -webkit-text-size-adjust 属性实现的:
    在这里插入图片描述
    Android
    Android通过给 webview 设置字体的缩放来完成,具体的API是setTextZoom(int)。
    在这里插入图片描述
    例如“文字大小10px”这一段文字被放大了两倍,随文字一同被放大的还有以em为单位的尺寸和line-height。

    于是很自然地想到,我们是否可以取到这些属性呢?

    // 取元素的fontSize
    document.querySelector(’.s10’).style.fontSize;
    结果很失望,取不到什么有用的信息。

    按iOS的方式,也取不到任何有用的样式,可见Android webview中并不是使用-webkit-text-size-adjust这个属性来放大文字的。

    一筹莫展之际,忽然想到是否应该取一下computedStyle?

    window.getComputedStyle(document.querySelector(’.fs10’),null).getPropertyValue(‘font-size’)
    这次终于有结果了,“文字大小10px”这一段文字明明白白地被使用了20px的文字大小!

    至此,我们可以大概推测出 Android webview 放大文字的原理:在CSS解析之后,渲染之前,将所有的字体大小的值进行缩放,后面的排版和渲染都会直接使用缩放后的CSS值。

    解决方案
    针对iOS,调整字体大小本身只是改变body的css属性,因此可以通过覆盖样式来控制。

    body {
    -webkit-text-size-adjust: 100% !important; }

    Android因为改变的是字体的大小,所以可以考虑将字体大小在设置的时候进行等比例缩小。例如,一个文字希望以10px来进行渲染,当webview被放大两倍时,此时font-size会变为20px。因此我们可以在取到这个放大比例之后,对原样式进行等比缩小,比如将原文字大小设置为5px,渲染的时候就变成了10px。

    var $dom = document.querySelector('.fs10');
    var originFontSize = 10;
    var scaledFontSize = parseInt(window.getComputedStyle($dom, null).getPropertyValue('font-size'));
    var scaleFactor = originFontSize / scaledFontSize;
    $dom.style.fontSize = originFontSize * scaleFactor;
    

    但是这样做仍然有几个问题:

    一次只能操作一个DOM元素,无法批量处理
    需要知道DOM元素原来设置的字体大小
    这几个问题并不如想象中的好解决。于是另辟蹊径,看看是否有一劳永逸的办法。脑海中很快冒出一个名词——rem!

    如果我们的页面字体大小都使用rem进行声明,那么我们就只需要在页面加载的时候根据缩放比例计算出html元素的字体大小即可!详见下方代码:

    (function(){
        var $dom = document.createElement('div');
        $dom.style = 'font-size:10px;';
        document.body.appendChild($dom);
        // 计算出放大后的字体
        var scaledFontSize = parseInt(window.getComputedStyle($dom, null).getPropertyValue('font-size'));
        document.body.removeChild($dom);
        // 计算原字体和放大后字体的比例
        var scaleFactor = 10 / scaledFontSize;
    
        // 取html元素的字体大小
        // 注意,这个大小也经过缩放了
        // 所以下方计算的时候 *scaledFontSize是原来的html字体大小
        // 再次 *scaledFontSize才是我们要设置的大小
        var originRootFontSize = parseInt(window.getComputedStyle(document.documentElement, null).getPropertyValue('font-size'));
        document.documentElement.style.fontSize = originRootFontSize * scaleFactor * scaleFactor + 'px';
    })();
    

    因为这段代码中创建了一个元素,并放入了document.body中,所以不能放在head中运行。如果放在页尾运行的话,则有可能会产生闪烁的情况,因此最好的办法是将这段代码放在开始的地方。

    除了在Android webview以外,以上代码在 Android 微信中实测也有效。

    其它方案
    Android微信
    在编写本文时,通过网上一些资料,发现在Android微信中,也可以借助WeixinJSBridge对象来阻止字体大小调整。实测也有效。

    (function() {
        if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") {
            handleFontSize();
        } else {
            document.addEventListener("WeixinJSBridgeReady", handleFontSize, false);
        }
        function handleFontSize() {
            // 设置网页字体为默认大小
            WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize' : 0 });
            // 重写设置网页字体大小的事件
            WeixinJSBridge.on('menu:setfont', function() {
                WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize' : 0 });
            });
        }
     })();
  • 相关阅读:
    C# GridView使用 与 DataList分页。
    如何禁止服务器端口 135 137 3389等
    页面自动刷新 与 隔时刷新
    彻底解决网页图片只能另存为无标题bmp位图
    C# Byte[]数组转化为string类型.其实很简单.
    vs2003打开时报错。尝试创建 Web 项目或打开位于..
    Discuz! 在线人数,发帖数,修改。
    点击文本框出现时间选择器DateJs
    一张有转折意义的神秘地图
    中断异常的处理
  • 原文地址:https://www.cnblogs.com/Alex80/p/15263294.html
Copyright © 2011-2022 走看看