当浏览器使用CSS中指定的备用字体而非主要字体时,是否有可能检测到?

20
如果在文本框中输入了一个字符,当前应用的字体不支持该字符,则该字符将使用备用字体。是否可以通过Javascript或其他方式告知此时发生了什么? 试图创建一个脚本,如果某个字符不受字体支持,就会向用户发出警报。感谢您的帮助!

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - T.J. Crowder
@T.J.Crowder 是的,没错 - Hendeca
1
如果当前字体不支持输入的字符,浏览器是否会真的使用其他字体? - adeneo
1
@adeneo 是的,可以确认在Chrome 48.0.2564.116中,如果您正在输入文本字段并且当前通过CSS应用的字体不支持字符。当键入支持的字符时,将再次使用主要的CSS字体。 - Hendeca
我确实有那种字体,但是使用一个网页安全字体会更好,这样更明显 -> https://jsfiddle.net/tjksf6fs/2/ - adeneo
显示剩余5条评论
2个回答

3
这似乎需要使用类似fontkit.jsopentype.js或甚至是Font.js这样的工具来测试字形支持性。这些工具可以测试自定义字体中的“孔洞”,但系统字体无法通过这种方式进行测试(Font.js 可能有效,但对于测试的字形可能会报告宽度为 0,这通常是“网络安全”字体,我们已经知道哪些字形被支持,因为每个人都在使用相同的字体)。然而,上述三种工具中的任何一种都应该已经实现了您想要实现的功能。

我对Font.js很感兴趣,因为它似乎是最简单的,也不是一个节点模块。但是,在阅读文档时,我无法弄清楚如何测试特定字形的存在。你能指导我实现这个功能的正确方法吗? - Hendeca
你正在寻找 font.measureText(textString, fontSize));,可能需要使用 forEach 循环来渲染所有需要呈现的字形。任何返回宽度为0的度量对象的 measureText 都不被所涉及的字体支持。 - Mike 'Pomax' Kamermans
1
请注意,我们不再生活在“仅适用于节点”或“仅适用于浏览器”的库的世界中。它们都是JS,因此大多数情况下,只要(就像对于纯浏览器解决方案一样)您安装了正确的shim,它们都会正常工作。例如 OpenType.js 可同时在两者中使用。FontKit.js 可以轻松地打包到浏览器中(使用 browserify --standalone 或类似工具),而只要您为其提供一个canvas shim,Font.js 就可以在Node中愉快地工作。 - Mike 'Pomax' Kamermans
谢谢!是的,这更多是关于解决方案对我的目的来说有多轻量级的问题。我认为如果我需要其他库的更多功能,我会更倾向于使用它们。 - Hendeca
我接受了这个答案,因为在我看来,这似乎是最可靠的方法。最终,我采取了一种完全不同的方法来解决这个问题(基本上只限制输入某些范围的ASCII字符),但我可以看到这可能有助于其他人。提交的两个答案都是有效的,但根据我的经验,另一个答案不太可靠,因此我认为这个答案“更正确”,因为我必须选择一个。 - Hendeca

3

通过检查字体中字符的宽度,并将其与备选字体进行比较,您可以推断出是否正在使用后备字体。该测试可能不是100%可靠的,但您可以执行以下操作:

var text = $(".main-text").html();
var chars = text.split("");
for(var i = 0, len = chars.length; i < len; i++){
 var str = chars[i]; str+=str;str+=str;str+=str;
 $("#test1, #test2").html(str);
 var w1 = $("#test1").width();
 var w2 = $("#test2").width();
 if(w1 == w2 && w1 != 0){
  alert("char not supported " + chars[i]);
 }
}
.main-text {
  width: 50%;
  height: 300px;
  font-family: Impact, sans-serif;
  font-size: 16px;
}
#test1, #test2 {
  position: fixed;
  top: -100px;
  font-size: 16px;
}
#test1 {
  font-family: Impact, sans-serif;
}
#test2 {
  font-family: sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea class="main-text">
Serif Font
This E is not supported: ể
</textarea>
<span id="test1"></span>
<span id="test2"></span>

jsfiddle


1
也许你需要在这里使用不同的字体定义“test1”和“test2”元素,这样才能更清晰。如果你设置了较大的字号,那么较小的差异也会被检测到。 - Kwebble
1
这是一个聪明的解决方案,尽管我发现它不能适用于所有字体。我尝试将字体更改回 Didot 作为测试,并发现每个字符都匹配为无效。我添加了一个事件侦听器来监听文本区域的更改,并通过val()而不是html()提取内容,以便我可以更改文本并获得实时结果以方便测试。https://jsfiddle.net/Hendeca/2xpLzuyk/ - Hendeca
这就是两年前我写https://github.com/Pomax/Font.js的原因=)为了保证100%的可靠性,它使用画布而不是HTML元素,然后进行行扫描以检查已涂色的像素。 - Mike 'Pomax' Kamermans
1
@Hendeca 我没有这个字体,所以无法测试,但您可以尝试添加额外的测试,使用不同的备用字体,例如 https://jsfiddle.net/tjksf6fs/5/ - jvilhena
@jvilhena 这个看起来好多了!我现在正在考虑使用这个解决方案还是使用一个库。感谢您提供这个方案。 - Hendeca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接