【问题标题】:Strange blurry text in HTML (canvas and svg)HTML 中奇怪的模糊文本(画布和 svg)
【发布时间】:2019-09-17 13:52:22
【问题描述】:

我的字体有一个奇怪的行为,文本在垂直(和水平但更难发现)“列”之后变得模糊。这是在画布和带有 chrome 的 svg 上测试的。两者的行为几乎相同。

看看 jsfiddle:https://jsfiddle.net/ryderone/m9kpjto3/170

或者看看下面的sn-p。

如您所见,我有非常清晰的字符和非常模糊的字符,具体取决于打印位置。

// test with canvas
var canvas = document.querySelector('#canvas');
var ctx = canvas.getContext('2d');
var coef = 1; // try to hidpi canvas, increase this to increase the ratio

canvas.width = 300 * coef;
canvas.height = 300 * coef;
document.fonts.onloadingdone = () => {
  ctx.fillStyle = '#ffffff';
  ctx.imageSmoothingEnabled = false;
  ctx.textBaseline = 'middle';
  ctx.font = (13 * coef) + 'px visitor2';

  for (var i = 1; i < 19; i++) {
    var x = 10;
    var y = 10 * i * coef + i;
    ctx.fillText(" AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   " + x + "/" + y, x | 0 + 0.5, y | 0 + 0.5);
  }
}

// same test with svg
var svg = document.querySelector('#svg');
for (var j = 1; j < 19; j++) {
  var x = 10;
  var y = 10 * j + j;
  var element = document.createElementNS('http://www.w3.org/2000/svg', 'text');
  element.setAttributeNS(null, 'x', x + '');
  element.setAttributeNS(null, 'y', y + '');
  element.style.fontFamily = 'visitor2';
  element.style.fontSize = '13px';
  element.style.fill = '#ffffff';
  var txt = document.createTextNode(" AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   " + x + "/" + y);
  element.appendChild(txt);
  svg.appendChild(element);
}
#canvas,
#svg {
  background: black;
  width: 300px;
  height: 300px;
}

@font-face {
  font-family: visitor2;
  src: url('https://ryder-one.github.io/hmap/visitor2.woff') format('woff');
}
<canvas id="canvas"></canvas>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300" height="300" id="svg"></svg>

请注意,上面的运行按钮不适用于画布(左侧),因为我没有加载字体。但是如果你多次按下运行,它就会在 jsfiddle 上工作。

我不认为这是一个亚像素画布的事情,因为它也在 SVG 上发生,具有完全相同的行为;而且我认为这也不是设备比率的事情。我不认为字体有问题,因为我已经看到了在 Flash 项目中使用的完全相同的字体,而且效果很好。

我基本上检查了所有关于画布上模糊文本和 HTML 的 SO 问题。我找到了一些有趣的答案,但没有找到任何描述这种确切行为的帖子。

有人知道什么会导致这种行为以及如何解决它吗?

谢谢!

编辑 1: Here is the picture of the problem

编辑 2: 请不要编辑帖子制作这张图片的缩略图,因为 SO 所做的调整大小隐藏了实际问题。单击链接以查看完整尺寸的图片。谢谢。

编辑 3:我在原帖中不够清楚。这不是与画布相关的问题,因为同样的问题也发生在 SVG 上。该帖子的一些查看者表示,他们无法通过浏览器重现该问题,画布和 SVG 都非常清晰。我正在考虑与 chrome 相关的问题或类似问题。

【问题讨论】:

  • Note that the run button above is not working properly 运行按钮工作正常,只是在绘制到画布之前您没有等待字体加载。我已经对您的 sn-p 进行了相当更新让它发挥作用,这比不得不跳到小提琴更好.. :)
  • SVG 在 Chrome 上看起来非常脆
  • 对于您的问题,我不确定我们在看什么问题,我在这里没有看到任何奇怪的模糊文本。小字体,是的,但在这里看起来很清晰。 Windows 上的 Chrome 73.0.3683.103。
  • 感谢装载机@Keith。我编辑了帖子以添加问题的屏幕截图。
  • 您可能想要更新该图片,因为它并没有完全展示您在说什么。我建议显示两张图片:一张基本图片(周围没有任何文本等,只需在两种上下文中显示“AAAAA”字符串作为排版),然后一些裁剪的缩放可以清楚地显示清晰与模糊。跨度>

标签: javascript fonts blurry


【解决方案1】:

这主要是你的字体的错。

它的字距设置不正确,会使这一系列字符落在浮动坐标上。
在某些时候,浏览器将不得不触发字体平滑算法。不同的操作系统和浏览器默认会使用不同的字体平滑算法,不同像素密度的屏幕或多或少会有明显的伪影;这可能就是为什么其他人看不到与您相同的结果(我看)。

除了向设计师抱怨外,你无能为力,它甚至可能出现在 HTML 中:

@font-face {
  font-family: visitor2;
  src: url('https://ryder-one.github.io/hmap/visitor2.woff') format('woff');
}
#test {
  font: 13px visitor2;
  line-height: 10px;
  padding: 10px;
}
<div id="test">
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
</div>

这是我在 macOS 上的 FF 上的外观(亚像素抗锯齿):

这是它在我的 Chrome 上的外观(灰度抗锯齿):


对于 SVG 和 HTML,您可以尝试禁用抗锯齿,尽管 IIIRC 仅适用于 MacOs 系统上的 Chrome,通过使用非标准 @ 987654323@ CSS 属性为none。但是这样做,浏览器将使用类似最近邻的算法,它只会在您的文本中创建一个间隙:

@font-face {
  font-family: visitor2;
  src: url('https://ryder-one.github.io/hmap/visitor2.woff') format('woff');
}
#test {
  font: 13px visitor2;
  line-height: 10px;
  padding: 10px;
  font-smooth: none; /* in case it works one day*/
  -webkit-font-smoothing: none; 
}
<div id="test">
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
AAAAAAAAAAAAAAAAAAAAAAAA<br>
</div>

这是我的 Chrome 上的样子:

所以是的,不再有模糊,但是在第 13 个字符之后你会得到一个很好的间隙。


对于,默认是透明抗锯齿,这是一种逻辑,因为浏览器不知道后面会画什么。
但是有一个鲜为人知的功能可以让我们在 macOS 上强制进行亚像素抗锯齿。通过使用alpha: false 选项启动我们的 2D 上下文,大多数浏览器会将字体平滑设置为亚像素:

document.fonts.onloadingdone = e => {
  // tell our context it won't have transparency
  const ctx = canvas.getContext('2d', {alpha: false});
  ctx.fillStyle = 'white';
  ctx.fillRect(0,0,canvas.width,canvas.height);
  ctx.fillStyle = 'black';
  ctx.font = (13) + 'px visitor2';
  for (var i = 1; i < 19; i++) {
    var x = 10;
    var y = 10 * i + i;
    ctx.fillText(" AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   " + x + "/" + y, x | 0 + 0.5, y | 0 + 0.5);
  }
  
  // draw close-up
  ctx.imageSmoothingEnabled = false;
  ctx.drawImage(canvas, -70, 70, canvas.width * 5, canvas.height * 5);
};
@font-face {
  font-family: visitor2;
  src: url('https://ryder-one.github.io/hmap/visitor2.woff') format('woff');
}
#canvas {
  font: 13px visitor2; 
}
&lt;canvas id="canvas" height="200"&gt;&lt;/canvas&gt;

所以至少现在,您可以在两种抗锯齿方法之间进行选择。

【讨论】:

  • 哇非常好的答案谢谢。出于多种原因,我选择了 SVG 而不是画布,所以如果我保留这种字体,我想我会被模糊所困扰。
猜你喜欢
  • 2016-10-29
  • 1970-01-01
  • 2023-03-20
  • 2021-05-27
  • 2013-07-25
  • 2018-07-22
  • 1970-01-01
  • 2018-04-10
  • 1970-01-01
相关资源
最近更新 更多