Canvas.measureText在浏览器上的差异是巨大的
编辑︰最初我只检查桌面浏览器 - 但与移动浏览器,图片更加复杂。Canvas.measureText在浏览器上的差异是巨大的
我遇到了一些有关浏览器和它的文本渲染功能的奇怪问题,我不确定我是否可以做任何事情来避免这种情况。
似乎WebKit和(不太一致)Android上的Firefox使用2D Canvas库创建稍大的文本。现在我想忽略视觉外观,而是将注意力放在文字测量上,因为可以轻松比较这些测量。
我已经使用了两种常见的方法来计算文本宽度:
- 画布2D API和测量文本
- DOM方法
在这个问题中概述:Calculate text width with JavaScript 然而,两者的结果都差不多(在所有浏览器中)。
function getTextWidth(text, font) {
// if given, use cached canvas for better performance
// else, create new canvas
var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
context.font = font;
var metrics = context.measureText(text);
return metrics.width;
};
function getTextWidthDOM(text, font) {
var f = font || '12px arial',
o = $('<span>' + text + '</span>')
.css({'font': f, 'float': 'left', 'white-space': 'nowrap'})
.css({'visibility': 'hidden'})
.appendTo($('body')),
w = o.width();
return w;
}
我修改了使用谷歌字体的小提琴一点,允许执行一组样品字体的文本度(请等待被点击测量按钮之前先加载网络字体):
http://jsfiddle.net/aj7v5e4L/15/ (更新强制字体粗细和样式)
运行此在各种浏览器显示(使用字符串“S”),我有问题:
所有桌面浏览器之间的差异都很小 - 只有Safari脱颖而出 - 根据字体的不同,它大约在我看过的1%和4%的范围内。所以它不是很大 - 但是抛弃了我的计算。
更新:测试了几个移动浏览器 - 在iOS上,所有与Safari相同的级别(在引擎盖下使用WebKit,所以没有惊喜) - 而且Android上的Firefox非常开关。
我读过所有浏览器(例如较老的IE浏览器)都不支持子像素精度 - 但即使舍入也无济于事 - 因为我可能会得到不同的宽度。
不使用webfont,只使用标准字体,上下文自带返回Chrome和Safari之间完全相同的测量值 - 所以我认为它仅与webfonts相关。
我对我现在可能做的事情有点困惑 - 因为我认为我只是做了一些错误的事情,因为我没有在网络上发现任何东西 - 但小提琴就像它可以得到的那样简单。我花了整整一天的时间 - 所以你们现在是我唯一的希望。
我头脑中有一些丑陋的解决方法(例如,在受影响的浏览器上渲染文本的4%小) - 我真的很想避免。
看来,Safari(和一些其他人)确实支持获取子像素级别,但不绘制...
当您将字号设置为9.5pt
时,此值将转换为12.6666 ... px。
即使Safari浏览器也换来这样的一个高的精度值:
console.log(getComputedStyle(document.body)['font-size']);
// on Safari returns 12.666666984558105px oO
body{font-size:9.5pt}
它无法在非整数字体大小正确绘制,而不是只在一个画布:
console.log(getRangeWidth("S", '12.3px serif'));
// safari: 6.673828125 | FF 6.8333282470703125
console.log(getRangeWidth("S", '12.4px serif'));
// safari: 6.673828125 | FF 6.883331298828125
console.log(getRangeWidth("S", '12.5px serif'));
// safari 7.22998046875 | FF 6.95001220703125
console.log(getRangeWidth("S", '12.6px serif'));
// safari 7.22998046875 | FF 7
// High precision DOM based measurement
function getRangeWidth(text, font) {
var f = font || '12px arial',
o = $('<span>' + text + '</span>')
.css({'font': f, 'white-space': 'nowrap'})
.appendTo($('body')),
r = document.createRange();
r.selectNode(o[0]);
var w = r.getBoundingClientRect().width;
o.remove();
return w;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
所以为了避免这些怪癖, 尝试始终使用带整数值的px
单位。
你的结果表是用字符串'“S”'做成的?如果是这样的话,我已经在第一个字体的firefox上获得了'15.73333..',这更接近你的Safari浏览器结果,而不是任何其他的。目前没有使用真正的键盘,但是当您强制使用字体重量时会发生什么? – Kaiido
是的,是用字符串“S”创建的 - 甚至没有触及移动浏览器的领域 - 这可能会引发更多问题;) - 将尝试字体重量 – Michael