是否可以检测浏览器何时使用后备字体而不是 CSS 中指定的主要字体?

Posted

技术标签:

【中文标题】是否可以检测浏览器何时使用后备字体而不是 CSS 中指定的主要字体?【英文标题】:Is it possible to detect when a browser is using a fallback font instead of the primary one specified in the CSS? 【发布时间】:2016-06-07 04:33:41 【问题描述】:

如果在文本字段中输入了一个字符,而当前应用的字体不支持该字符,则会为该字符使用备用字体。发生这种情况时是否可以通过 javascript 或其他方式进行判断?尝试创建一个脚本,如果字体不支持某个字符,该脚本会提醒用户。感谢您的帮助!

【问题讨论】:

所以要非常清楚:浏览器有字体(而不是当你指定font-face: wanglebrat, sans-serif而浏览器没有wanglebrat,所以它使用sans-serif),但是您想知道特定字符何时丢失,对吗? @T.J.Crowder 是的,没错 如果一个字符被输入到当前字体不支持的输入中,浏览器真的会使用不同的字体吗? @adeneo 是的,如果您正在输入文本字段并且当前通过 CSS 应用的字体不支持该字符,则可以确认在 Chrome 48.0.2564.116 中。当键入支持的字符时,将再次使用主要的 css 字体。 我想我从来没有见过这种情况,你能否设置一个我们可以玩的最小示例,并尝试弄清楚如何知道浏览器何时使用不同的字体。 【参考方案1】:

这听起来像是fontkit.js 或opentype.js 甚至Font.js 之类的工作,所有这些都可以测试字体是否支持字形。系统字体没有以这种方式覆盖(Font.js 可能会工作,它可能会为测试的字形报告宽度 0)但是这些通常是“网络安全”字体,我们已经确切知道哪些字形是受支持的,因为每个人都使用相同的。但是,为了测试自定义字体中的“孔”,前面提到的三个中的任何一个都应该已经完成​​了您打算实现的操作。

【讨论】:

我对 Font.js 很感兴趣,因为它似乎是最简单的并且不是节点模块,但是在阅读文档时我不太清楚如何测试是否存在特定字形的。你能指出实现这一目标的正确方法吗? 您正在寻找font.measureText(textString, fontSize));,可能是作为所有需要渲染的字形的forEach 循环。任何产生宽度为 0 的度量对象的 measureText 都非常不支持相关字体。 还请注意,我们不再生活在“仅适用于节点”或“仅适用于浏览器”库的世界中。都是 JS,所以大多数时候,只要(就像纯浏览器解决方案一样)你有正确的垫片,这两种方法都可以正常工作。例如,OpenType.js 在这两种情况下都适用。 FontKit.js 可以简单地与浏览器捆绑在一起(使用 browserify --standalone 或其他东西),并且 Font.js 将很高兴地在 Node 中工作,只要你可以为它填充一个画布。 谢谢!是的,对于我的目的而言,解决方案的轻量级更多是一个问题。我想如果我需要其他库的更多功能,我会更倾向于使用它们 我接受了这个答案,因为在我看来这是最可靠的方法。我最终采取了一种完全不同的方法来解决这个问题(基本上将输入限制在特定范围的 ascii 字符中),但我可以看到这可能会使其他人受益。提交的两个答案似乎都有效,但根据我的经验,另一个不太可靠,因此我认为这个“更正确”,因为我必须选择一个。【参考方案2】:

检查字体中字符的宽度,并将其与后备字体进行比较,您可以推断它是否使用后备字体。此测试可能不是 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

【讨论】:

也许不清楚您需要在此处使用不同的字体系列定义test1test2 元素。如果您在它们上设置较大的字体大小,则会检测到较小的差异。 这是一个聪明的解决方案,尽管我发现它不适用于所有字体。我尝试将字体改回 Didot 作为测试,发现每个字符都匹配为无效。我添加了一个事件侦听器,它侦听文本区域的更改并通过 val() 而不是 html() 拉取内容,以便我可以更改文本并查看实时结果以方便起见。 jsfiddle.net/Hendeca/2xpLzuyk 这就是我在 2 年前写的 github.com/Pomax/Font.js =) 为了 100% 可靠,它使用画布,而不是 html 元素,然后进行行扫描以检查绘制的像素. @Hendeca 我没有字体,所以我无法测试它,但您可以尝试使用不同的备用字体添加额外的测试,例如jsfiddle.net/tjksf6fs/5 @jvilhena 这似乎工作得更好!我目前正在尝试在此解决方案和使用库之间做出决定。感谢您提供这个。

以上是关于是否可以检测浏览器何时使用后备字体而不是 CSS 中指定的主要字体?的主要内容,如果未能解决你的问题,请参考以下文章

材质图标的 css 后备

使用 iTextSharp 的后备字体

jQuery-File-Upload iframe 后备检测

是否可以使用浏览器专用的字体?

IE8 的 calc() 是不是有纯 CSS 后备

css动画后文本“轻推”自身