amfe / article

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Font Boosting

mingelz opened this issue · comments

最近在做一个手机端页面时,遇到了一个奇怪的问题:字体的显示大小,与在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-height, min-width, max-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了。。。-_-!!!

Update 2015-7-24:
@yisibl 姐姐说,用 max-height: 100% 可能会更好一些。

Ref.

  1. Webkit Bug 84186 Webkit Bugs 上记录的这个问题,最早从 2012 年 4 月份就开始讨论这个问题了,但好像都没有引起我们的任何关注。
  2. Chromium's Text Autosizer 关于 Font Boosting 最重要的一篇文章,更确切的说是论文。
  3. Font boosting in mobile browsers
  4. Font Boosting 一个俄国人用英文写的文章。
  5. 一堆 StackOverflow 上的问答,用 Font Boosting 搜可以出来一大坨,这里就不列了。
commented

good!

commented

Nice boat!

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">
commented

哈哈,今天也刚发现这个问题,在stackoverflow找到的答案http://stackoverflow.com/questions/13416989/computed-font-size-is-bigger-than-defined-in-css-on-the-asus-nexus-7

不过,除了max-height, 貌似min-height、min-width、max-width这几个并不能解决font-boosting的问题啦,楼主确认下?

@ovaldi 确实如此,多谢指正。看来不亲自测一下是不能随便乱写的。

太好了。。这个情况发生的时候我也爆头了。。

太棒,困恼我好久的问题。

我第一反应就是看了下meta标签,果然是没有加meta标签。。。 回头看看评论 ,一丝大神已经写了。。。。不过大概width不是devide-width或者initial-scale不是1的时候不正好是需要缩放的么。。。。

niubility

在meta里面加入devide-width或者initial-scale可以限制缩放的。

commented

马克一下

受教育程度超过小学6年!

感谢分享!Github Wiki在移动端也会autosize,原来是可以避免的。

commented

我去...终于找到原因了....泪目.....
被这个坑爹的问题折磨了两天了....
24px比32px还大你敢信?...宽度减小字突然变小是什么鬼....
原来都是这坑货捣的鬼..

@riskers 淘宝 flexible 默认是可能触发 foot-boosting 的,我也是在 flexible 环境下发现的这个问题。

同样也遇到过这个问题,原来是font-boosting。

特地赶来赞一个

我们团队曾经也遇到过这个问题,最后加了一个max-height解决,在stackoverflow找的方案。

泪流满面T-T

* {
    padding: 0;
    margin: 0;
    max-height: 100000000px;
}

当我这么写的时候一些iPhone在渲染页面时候一场不能识别元素高度 。
比如这个紫色div设置了1090px的高度但是无效。
qq 20160118224255
换成max-height: 999999px;也会在iPhone的QQ浏览器中出问题。

如果mobile开发中采用淘宝 flexible方案,想解决Font Boosting问题
1,设置max-height: 999999px;
2, 整个页面滚动条采用isroll

前几天刚遇到,学习了!

好顶赞,郁闷了好久,从 sf 过来的

thanks

commented

顶,终于解决了

mark

我也是遇到这个问题。。。用 淘宝的 flexble.js ,出现了字体大小显示不一样 用楼主的方法可以解决

去年就发现问题,也是用的淘宝的 flexble.js,当时还是第一版吧,实在没解决,就放弃这个方法····原来解决的方法是这样,看来以后可以愉快的用了

Mark 先,以后忘了还可以找回来看看。

commented

记录一下

收藏!

commented

mark!同样是用的手淘的flexble.js发现的这个问题,多谢楼主

mark!!谢谢楼主!

mark, 谢谢楼主!在小米手机上碰到了这问题!

完美!

泪流满面

commented

其实一丝冰凉是男的兄弟-。-

之前也遇到过类似问题,当时是忘记加meta了,但一直不明白引发的原因是什么,学习了,赞!!

@loudou140806 一丝姐姐是爱称 :)

困扰了我两天的问题,终于解决了,多谢

mark一下,前段时间在做项目的时候遇到类似问题,不过并不是通过设置max-height解决的,我们的是html5页面嵌入原生app中,在调试的时候发现所有渲染出来的文字都是原始设置值的80%。最后是原生方面设置了针对webview文字的属性解决了这个问题

commented

困扰了很久的问题终于解决了, 太感谢了!

话说,设置好 viewport 就是了,还搞这么多?

尝试了一下,是可以解决问题,但如果是td的文字变大了,这其中说的三种方法,只有给height 而不是max-height 但高度又不确定,所以现在很纠结,有没有解决方法是解决这个问题的基础上,解决td文字变大的?

@floraluo 怎么解决的 烦请说下,我也遇到了只有在mx的情况下

用淘宝的flexble.js ,刚好碰到这问题 谢楼主咯

我碰到的问题是,设置同样大小的值但是转出来的rem不一样

  height: 76px; 
  line-height: 76px;

qq 20170410143752

commented

mark

楼主这个比我的效果好,我最近也遇到了,解决方案是给写了font-size的标签写上:display:inline-block或者flex,然后要是不行再加上min-height:1px就好了,但是好麻烦,我的是文字一多了就遇到这个问题了

最近发现一个新的属性,专门解决楼主说的问题
text-size-adjust:auto | none |

...我刚好使用了楼上仁兄的,好用

commented

@gesilaGRY text-size-adjust目前还在draft阶段,Browser的support情况目前来看还不理想,如下图:
image

所以现阶段感觉还是使用max-height相对好一些,:)

6666666666666 感谢

commented

mark一下

Thanks

niubility

mark

感谢

我对.... CSS 的力量一无所知...

6得不行

感谢楼主分享的方法,今天碰到了就解决了### ****

commented

mark

commented

mark!Orz..

commented

为什么我在安卓微信浏览器试了没有效果。。

最近发现一个新的属性,专门解决楼主说的问题 text-size-adjust:auto | none |

我也遇到这个鬼玩意儿了:
本来在 android opera 里几下搞好就满意的去干别的了, 后来发现 android chrome 表现鬼畜.
明明写的 font-size:12px !important, 在 android chrome (或 pc chrome F12 mobile 模式) 里 被渲染成 30多px.

从 1~30px 调整 font-size, 字体还不是连续变化的, 中间会突变一下.
// 非常抓狂!!


我用最上面 metamax-height 方案无效.
// 有些后面动态创建的元素 显示不对.


自己摸索的是用这个可以. (android chrome 97)

 body * {
        max-height: 9999px !important; 
        overflow-y: hidden;
}

不过加上 overflow-y 的方式 总感觉解决方案不干净.


上面同学说的 这个 专用的 text-size-adjust 确实好用.
👍 👍 👍

 body * {
        text-size-adjust: none;
}

// 又念头通达了.

这个鬼特性 不知道残害了多少程序员 😿