Javascript 浏览器上的Canvas.measureText差异很大

Javascript 浏览器上的Canvas.measureText差异很大,javascript,canvas,safari,webkit,measurement,Javascript,Canvas,Safari,Webkit,Measurement,编辑:最初我只检查桌面浏览器-但对于移动浏览器,图片更复杂 我在一些浏览器及其文本呈现功能方面遇到了一个奇怪的问题,我不确定我是否能做些什么来避免这个问题 Android上的WebKit和(不太一致的)Firefox似乎正在使用2D画布库创建稍大的文本。我现在想忽略视觉外观,而是将重点放在文本测量上,因为这些可以很容易地进行比较 我使用了两种常用的方法来计算文本宽度: 画布2D API和度量文本 DOM方法 如本问题所述: 然而,两者产生的结果或多或少相同(在所有浏览器中) 函数getTex

编辑:最初我只检查桌面浏览器-但对于移动浏览器,图片更复杂

我在一些浏览器及其文本呈现功能方面遇到了一个奇怪的问题,我不确定我是否能做些什么来避免这个问题

Android上的WebKit和(不太一致的)Firefox似乎正在使用2D画布库创建稍大的文本。我现在想忽略视觉外观,而是将重点放在文本测量上,因为这些可以很容易地进行比较

我使用了两种常用的方法来计算文本宽度:

  • 画布2D API和度量文本
  • DOM方法
如本问题所述: 然而,两者产生的结果或多或少相同(在所有浏览器中)

函数getTextWidth(文本、字体){ //如果给定,请使用缓存画布以获得更好的性能 //否则,创建新画布 var canvas=getTextWidth.canvas | |(getTextWidth.canvas=document.createElement(“canvas”); var context=canvas.getContext(“2d”); context.font=font; var metrics=context.measureText(text); 返回度量。宽度; }; 函数getTextWidthDOM(文本、字体){ var f=font | |“12px arial”, o=$(''+文本+'') .css({'font':f,'float':'left','white space':'nowrap'}) .css({'visibility':'hidden'}) .appendTo($(“body”), w=o.宽度(); 返回w; } 我使用Google字体稍微修改了fiddle,允许对一组示例字体执行文本测量(请等待webfonts先加载,然后单击测量按钮):

(更新为强制字体大小和样式)

在各种浏览器上运行此命令显示了我遇到的问题(使用字符串'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']);
//在Safari上返回12.6666984558105px oO

body{font-size:9.5pt}
我发现下面的MDN解决方案对于字体倾斜/斜体的场景更有用,这对我来说是一些谷歌字体的例子

从此处复制代码段-


您的结果表是用字符串
“S”
?如果是这样的话,我在firefox for android的第一个字体上有
15.73333..
,它比其他任何字体都更接近您的safari结果。现在还不能使用真正的键盘,但是当你强制使用字体时会发生什么呢?是的,是用字符串“S”创建的-甚至没有触及移动浏览器的领域-这可能会带来更多的问题;)-将尝试字体权重,非常棒-快速查看,使用以像素为单位的整数字体大小,看起来确实是一致的(需要再做一些检查)。一个新的提琴演示了这一点,并允许动态编辑字体大小:非常感谢Kaido,这真的很有帮助。
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;
}
const computetextWidth = (text, font) => {
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');

    context.font = font;
    const { actualBoundingBoxLeft, actualBoundingBoxRight } = context.measureText(text);
    return Math.ceil(Math.abs(actualBoundingBoxLeft) + Math.abs(actualBoundingBoxRight));
}