子集数字,让它们与你的其他内容一样出色

Avatar of Charlotte Dann
Charlotte Dann

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

您正在为您的百万美元创意添加最后的润色——您的文案完美无瑕,您的配色方案令人眼花缭乱,您找到了一对绝妙的字体组合(谁能想到 Baskerville 和 Raleway 如此般配?您想到了。)但有一个问题:Raleway 恼人的小写数字让您的购物车看起来很混乱,并给用户带来不必要的负担。

这是一个相当普通的问题,但如果数字是您网站的重要组成部分,则可能会导致漂亮的字体无法使用;例如商店或分析仪表板。而这不仅仅是小写数字的问题。当浏览数字列表时,非等宽数字也同样令人分心。

我们将研究一些解决此问题的方法,但首先我们需要找到一种字体,其数字可以替代我们主体字体。没有现成的找到字体孪生体的方法。搜索时最重要的特征是字体粗细和宽度,以便您可以将其与原始字体相匹配。如果您打算在多种粗细下使用数字,请尝试查找具有广泛粗细范围的字体,以增加匹配原始字体的机会。您最终可能需要为每种粗细使用不同的数字字体,或者使字体对的粗细不匹配,但这没关系,因为实际上没有字体警察

以下是一些 Google 字体组合,它们在较小尺寸下匹配得足够好,以至于不会引起注意

方法 0:将它们包裹在 spans 中

@import url('https://fonts.googleapis.com/css?family=Raleway:400|Nunito:300');

body {
  font-family: 'Raleway', sans-serif;
}

.numeral {
  font-family: 'Nunito', 'Raleway', sans-serif;
}
Your total comes to $<span class="numeral">15</span>.<span class="numeral">99</span>

这不是一个好的解决方案。不得不修改标记是不好的,并且完整加载两种字体也不是很好,但是如果您内容不多并且想要一个简单的解决方案,那么这样做也无可厚非。

我们更希望找到一个纯 CSS 解决方案,该解决方案隔离数字字体的数字并加载它们,而不是(或在主字体之前)无需更改HTML。继续阅读。

font-family 的工作原理

以下方法依赖于创建@font-face声明,该声明仅引用我们首选的数字子集,并在字体堆栈中像往常一样引用它们

body {
  font-family: 'Custom Numeral Font', 'Main Font', sans-serif;
}

通过在您的font-family声明中首先排序子集字体,浏览器将默认为它,并将回退到后续字体以获取第一个字体中不可用的字形。这是一个非常重要的区别——浏览器不仅检查声明的字体是否可用(本地或通过@font-face导入),还检查其字符映射是否包含请求的字符,如果它没有,则会逐个字符传递到下一个字体。顺便说一句,规范对于字体匹配算法来说是一个非常有趣的阅读。

需要注意的是,浏览器会优先考虑字体系列而不是字体粗细和样式,因此,如果您仅为普通粗细子集数字,然后在粗体样式元素内有数字,则浏览器将选择显示来自数字字体的普通粗细字符,而不是主字体的粗体字符。基本上,如果您这样做,请确保您对将显示数字的所有字体粗细都执行此操作。

方法 1:Font Squirrel 自定义子集

如果您自托管字体文件而不是从 Adobe Fonts 或 Google Fonts 等托管服务提供它们,则可以使用Font Squirrel 的 Webfont Generator的专家配置来创建仅包含数字子集的文件。在继续操作之前,请阅读字体的许可协议,以确保此类操作是可以的。

在 Font Squirrel 界面中将替换字体的字符类型设置为数字。

获得子集字体文件后,您可以像往常一样使用它们。查看这篇文章以获取有关@font-face和文件类型浏览器支持的更多信息。

@font-face {
  font-family: 'Nunito';
  src: url('nunito-light-webfont.woff2') format('woff2'),
        url('nunito-light-webfont.woff') format('woff');
  font-weight: normal;
  font-style: normal;
}

body {
  font-family: 'Nunito', 'Raleway', sans-serif;
}

如果您注重性能,还可以对主字体进行子集化以删除其数字字形并减少一些额外的字节。

方法 2:@font-face unicode-range 子集

@font-faceunicode-range属性主要用于声明字体文件包含的字符集,以帮助浏览器决定是否下载文件;对于使用非拉丁字母的多语言网站来说,这极大地提升了性能。另一方面,unicode-range限制@font-face声明到指定的范围,这意味着我们只能用它来使字体文件的部分内容在浏览器中可用。

@font-face {
  font-family: 'Nunito';
  src: url('nunito-light-webfont.woff2') format('woff2'),
       url('nunito-light-webfont.woff') format('woff');
  font-weight: normal;
  font-style: normal;
  unicode-range: U+30-39; /* 0-9 /
}

body {
  font-family: 'Nunito', 'Raleway', sans-serif;
}

这比之前的方法性能更差,因为浏览器仍然必须下载整个字体文件才能使用数字,但如果许可协议不允许修改文件,则更可取。

遗憾的是,我们无法使用此方法对外部服务已加载的字体进行子集化,但它可以用于本地字体

@font-face {
  font-family: 'Times Numeral Roman';
  src: local('Times New Roman');
  unicode-range: U+30-39; /* 0-9 */
}

这是一种调整主字体特定字符的巧妙方法,也许只对一个&符号或首选的弯引号进行子集化(在这种情况下,您必须放弃“Times Numeral Roman”的双关语),并且不会造成性能损失,因为如果本地字体不存在,它将被忽略。您可以在这里查看常见系统字体的可用性。并且您可以成为字体极客的女王,通过创建一个只能在您本地下载了所有子集字体的网站才能正确欣赏的网站,高级且神秘。

unicode-range的支持非常好,但请注意,如果它不受支持,则子集字体将用于所有文本,因此,也许不要将其设置为 Papyrus。或者,如果您真的想使用 Papyrus,您可以偷偷摸摸地在前面添加另一种网络安全字体,以便不支持的浏览器默认为它而不是 Papyrus

@font-face {
  font-family: 'Backup Font';
  src: local('Arial');
  unicode-range: U+60; /* backtick because I can't think of a more innocuous character */
}

@font-face {
  font-family: 'Papyrus Ampersand';
  src: local('Papyrus');
  unicode-range: U+26; /* & */
}

body {
  font-family: 'Backup Font', 'Papyrus Ampersand', 'Main Font', sans-serif;
}

方法 3:Google Fonts 文本子集

Google Fonts API 附带了一些方便的额外选项,通过仅指定特定的字体粗细、样式和字母表来帮助优化(subset参数采用字母表列表,如greek,cyrillic,而不是 unicode 范围,遗憾的是),但还有一个鲜为人知的“beta”参数称为text,它表面上用于标题和徽标,但同样适用于我们的目的

@import url('https://fonts.googleapis.com/css?family=Raleway:400');
@import url('https://fonts.googleapis.com/css?family=Nunito:300&text=0123456789');

body {
  font-family: 'Nunito', 'Raleway', sans-serif;
}

如此简单!如此优雅!

text参数可以接受任何 UTF-8 字符,但是如果它们不是字母数字,请确保URL 编码它们。此方法唯一可能存在的问题是,我们没有使用@font-face创建自定义名称,因此,如果用户已经在其系统上拥有子集字体,它将完整使用该字体。

我还没有找到任何其他托管字体服务提供这种级别的子集粒度,但如果您遇到任何一个,请在下面发表评论。

一些用例

实时演示
实时演示
实时演示
实时演示