您正在为您的百万美元创意添加最后的润色——您的文案完美无瑕,您的配色方案令人眼花缭乱,您找到了一对绝妙的字体组合(谁能想到 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-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-face
的unicode-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
创建自定义名称,因此,如果用户已经在其系统上拥有子集字体,它将完整使用该字体。
我还没有找到任何其他托管字体服务提供这种级别的子集粒度,但如果您遇到任何一个,请在下面发表评论。
一些用例




不错的技巧,谢谢!在搜索可接受的字体孪生体之前,您还可以查看您选择的字体是否已包含您需要的数字。例如,Raleway 包含衬线数字(但不是比例数字),Monserat 具有衬线和旧式数字——比例数字和等宽数字。
如果字体中可用,您可以使用 CSS 字体功能设置激活所需的数字,例如,对于等宽(表格)数字
.dashboard { font-feature-settings: ‘tnum’; }
或者如果您的浏览器已支持它
.dashboard { font-variant-numeric: tabular-nums; }
您可以将它们组合起来,具体取决于您是想使用表格衬线还是表格旧式数字(‘tnum’,‘lnum’;或 ‘tnum’,‘onum’;)。
在阅读文本时,旧式(比例)数字融合得更好,因此请使用
article { font-feature-settings: ‘onum’, ‘pnum’; }
分别
article { font-variant-numeric: oldstyle-nums proportional-nums; }
如文中所说:这只有在你的字体文件中包含所需的数字集作为替代方案时才有效。但它们将完美地契合,并且在大多数情况下比其他类似字体更好。
此请求,https://fonts.googleapis.com/css?family=Nunito:300&text=0123456789,返回
这里没有
unicode-range
描述符。这是否意味着,如果用户本地安装了'Nunito Light'
,该字体将用于不仅仅是数字(即,其余字体堆栈将完全被忽略)?我用一组不同的字符进行了检查,并得到了一个不同的kit=参数;此外,字体文件看起来相当小。我想该字体只包含这10个字符以及文章中描述的常用回退。(G在浏览器嗅探方面相当出色,可以向您发送仅包含有效部分的CSS,我一点也不惊讶如果它们向Chrome等发送不同的字体加上unicode-range,以提高可缓存性。)
是的,字体文件是子集化的,但我询问的是用户本地安装了该字体的情况(注意
local('Nunito Light')
部分)。在这种情况下,不会使用该子集化的字体文件,而是使用完整的本地字体,对吧?如果这是正确的,我认为Google Fonts也需要包含相应的
unicode-range
,以确保本地字体仅用于子集化字体文件中可用的相同字符。这是一个解决问题的巧妙CSS技巧,但为了确保每个人都正确理解排版
“小写”数字称为旧式,替代方案称为衬线。我认为通常,如果字体有旧式数字,它也具有衬线数字……但有时反之则不然。
“等宽”数字称为表格,而不是比例,同样……大多数(好的/专业的)字体都同时具备。
看起来您可以通过
font-feature-settings
或font-variant-numeric
来更改数字的样式,尽管看起来某些浏览器对这些的支持可能存在问题。也许您可以使用子集化来仅包含您需要的样式(诚然,我不知道这些是如何存储/访问在unicode中……)。无论您如何操作——1.) 您的字体可能已经包含您可以使用的更好的数字字形集,以及2.)
等宽
≠表格……如果将这些混淆,设计师会非常反感。您可以使用
@supports
来指示现代浏览器更改字体功能设置以进行平滑过渡,并让旧版浏览器回退到加载两种字体。根据https://caniuse.cn/#search=font-feature-settings,对font-feature-settings的支持非常好(92%,除了Opera Mini和IE移动版)。考虑到如果例如tnum失败,网站仍然可以完美使用……
与其使用@supports进行操作,我只需使用https://www.fontsquirrel.com/tools/webfont-generator对我的字体文件进行子集化(如果数字可用且许可证允许)。因此,您可以创建将所需的数字作为默认值的字体文件。我为我的博客做了这个,以便在文本中使用Source Sans的旧式数字。