zoukankan      html  css  js  c++  java
  • flexible.js字体大小诡异现象解析及解决方案

    最近在做一个手机端页面时,遇到了一个奇怪的问题:字体的显示大小,与在CSS中指定的大小不一致。大家可以查看这个Demo(记得打开Chrome DevTools)。

    Font Boosting Test

    就如上图所示,你可以发现,原本指定的字体大小是24px,但是最终计算出来的却是53px,看到这诡异的结果,我心中暗骂一句:这什么鬼!

    随后开始对问题各种排查:某个标签引起的?某个CSS引起的?又或者是某句JS代码引起的。通过一坨坨的删代码,发现貌似都不是。我不禁又骂,到底什么鬼!不过中间还是发现了一些端倪:当页面中的标签数量或者文本数量大于某一个值,或者当CSS定义的字体大小落在某个区间时,这个问题才会被触发。而且字体变大后的值也随着原始定义的字体大小而改变。

    然后自然就是各种搜索,终于有了新的发现。原来这个特性被称做「Text Autosizer」,又称「Font Boosting」、「Font Inflation」,是 Webkit 给移动端浏览器提供的一个特性:当我们在手机上浏览网页时,很可能因为原始页面宽度较大,在手机屏幕上缩小后就看不清其中的文字了。而 Font Boosting 特性在这时会自动将其中的文字字体变大,保证在即不需要左右滑动屏幕,也不需要双击放大屏幕内容的前提下,也可以让人们方便的阅读页面中的文本。

    不过这个特性并不总是有必要的,还好在查到问题原因的同时,大家也讨论了对这个问题的一些处理方案:

    1. 手动指定 viewport width=320,这时 Font Boosting 不会被触发。(后边可以知道,这个说法不严谨,在其他设置均为默认值时,这一条才有效)
    2. Font Boosting 仅在未限定尺寸的文本流中有效,给元素指定宽高,就可以避免 Font Boosting 被触发。
    3. 显然第 2 条方案是有缺陷的,文本内容不可能都指定宽高。不过还好,我们通过指定 max-height ,min-heightmin-widthmax-width(经 @Ovaldi 指正,只有 max-height 有效) 也是可以的。比如body * { max-height: 999999px; } 就可以无副作用的禁掉 Font Boosting 特性。当然,我觉得没必要使用通用选择器,用类似 p { max-height: 999999px; } 可能更好一些。

    到这里,我们已经明白问题所在,并且也有解决方案了。但是有一个问题仍然困扰着我:当字体大于某一个值时(比如当不指定viewport width,手机屏幕width=320,字体大于等于82px时),这个 Font Boosting 就始终不会被触发。Chrome 是如何计算的,这其中的逻辑又是什么?

    这一次问题解决起来就没有那么容易了,我先是各种搜索无果,然后自己人肉去试,慢慢找规律,但是发现变化不是线性的,看来这个公式还比较复杂。终于在今天被我发现了这篇文章:Chromium's Text Autosizer,彻底解释了我的疑问。

    Font Boosting 具体的实现代码在 TextAutosizer.cpp 这个文件中可以看到,有兴趣的可以翻一下。

    简单说来,Font Boosting 的计算规则伪代码如下:

    multiplier = Math.max(1, deviceScaleAdjustment * textScalingSlider * systemFontScale * clusterWidth / screenWidth);
    if (originFontSize < 16) {
        computedFontSize = originFontSize * multiplier;
    }
    else if (16 <= originFontSize <= (32 * multiplier - 16)) {
        computedFontSize = (originFontSize / 2) + (16 * multiplier - 8);
    }
    else if (originFontSize > (32 * multiplier - 16)) {
        computedFontSize = originFontSize;
    }

    其中变量名解释如下,更具体的说明可以参考上边的两个链接。

    • originFontSize: 原始字体大小
    • computedFontSize: 经过计算后的字体大小
    • multiplier: 换算系数,值由以下几个值计算得到
      • deviceScaleAdjustment: 当指定 viewport width=device-width 时此值为 1,否则值在 1.05 - 1.3 之间,有专门的计算规则
      • textScalingSlider: 浏览器中手动指定的缩放比例,默认为 1
      • systemFontScale: 系统字体大小,Android设备可以在「设备 - 显示 - 字体大小」处设置,默认为 1
      • clusterWidth: 应用 Font Boosting 特性字体所在元素的宽度(如何确定这个元素请参考上边两个链接)
      • screenWidth: 设备屏幕分辨率(DIPs, Density-Independent Pixels),如 iPhone 5 为 320

    说了这么多,貌似只需要记住 p { max-height: 999999px; } 就OK了。。。-_-!!!

    用 max-height: 100% 可能会更好一些。

     

    WebKit 中应该有判断如果initial-scale=1时,不触发Font Boosting。

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 或 -->
    <meta name ="viewport" content ="initial-scale=1, maximum-scale=1, minimum-scale=1">


  • 相关阅读:
    mysql索引
    springboot mybatis 后台框架平台 shiro 权限 集成代码生成器
    java 企业网站源码模版 有前后台 springmvc SSM 生成静态化
    java springMVC SSM 操作日志 4级别联动 文件管理 头像编辑 shiro redis
    activiti工作流的web流程设计器整合视频教程 SSM和独立部署
    .Net Core中的ObjectPool
    文件操作、流相关类梳理
    .Net Core中的配置文件源码解析
    .Net Core中依赖注入服务使用总结
    消息中间件RabbitMQ(一)
  • 原文地址:https://www.cnblogs.com/axl234/p/5895347.html
Copyright © 2011-2022 走看看