amfe / article

7.58k stars 1.07k forks source link

Font Boosting #10

Open mingelz opened 9 years ago

mingelz commented 9 years ago

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

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

说了这么多,貌似只需要记住 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 搜可以出来一大坨,这里就不列了。
bsed commented 9 years ago

good!

banrikun commented 9 years ago

Nice boat!

yisibl commented 9 years ago

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">
ovaldi commented 9 years ago

哈哈,今天也刚发现这个问题,在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的问题啦,楼主确认下?

mingelz commented 9 years ago

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

fish-ball commented 9 years ago

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

bluest-hu commented 9 years ago

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

sweet-zone commented 9 years ago

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

qingying commented 9 years ago

niubility

stanleyxu2005 commented 9 years ago

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

jiraa commented 8 years ago

马克一下

Iamlars commented 8 years ago

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

geeeeeeeeek commented 8 years ago

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

ql2005 commented 8 years ago

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

mingelz commented 8 years ago

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

Thinking80s commented 8 years ago

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

FrankFang commented 8 years ago

特地赶来赞一个

sjclijie commented 8 years ago

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

MicleMing commented 8 years ago

泪流满面T-T

bluest-hu commented 8 years ago
* {
    padding: 0;
    margin: 0;
    max-height: 100000000px;
}

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

xushuwei202 commented 8 years ago

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

jin5354 commented 8 years ago

前几天刚遇到,学习了!

ystarlongzi commented 8 years ago

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

johanninos commented 8 years ago

thanks

imcamo commented 8 years ago

顶,终于解决了

gaofant101 commented 8 years ago

mark

supidea commented 8 years ago

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

missfanfan commented 8 years ago

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

Megasu commented 8 years ago

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

caogy commented 8 years ago

记录一下

bytemofan commented 8 years ago

收藏!

YL2014 commented 8 years ago

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

wx85745997 commented 8 years ago

mark!!谢谢楼主!

hexuanzhang commented 8 years ago

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

skyzhao1223 commented 8 years ago

完美!

xilin commented 8 years ago

泪流满面

loudou140806 commented 8 years ago

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

yuanxj1024 commented 8 years ago

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

mingelz commented 8 years ago

@loudou140806 一丝姐姐是爱称 :)

ghost commented 8 years ago

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

floraluo commented 8 years ago

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

Vivomo commented 8 years ago

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

jerrybendy commented 8 years ago

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

yan-gitHub commented 8 years ago

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

lin-hun commented 7 years ago

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

wangmiaoduan commented 7 years ago

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

CodeDreamfy commented 7 years ago

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

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

qq 20170410143752

Keystion commented 7 years ago

mark

gesilaGRY commented 7 years ago

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

bohancen commented 7 years ago

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