在web上使用emoji

默认情况下,大多数浏览器使用底层操作系统提供的表情符号字体。运行在ChromeOS和大多数Android设备上的浏览器能显示谷歌的Noto Color Emoji。在iOSmacOS上,浏览器将使用苹果彩色表情符号,而在Windows上则会使用微软的Segoe Color EmojiWindowsLinux上的Firefox是个例外,它捆绑了TwitterTwemoji字体,而不是使用Segoe

当您在HTML标记中使用表情符号字符时,表情符号正常显示。然而,需要注意的是,有一些边缘情况和问题。

1. 单色图标

一些较旧的表情符号(见此处的完整列表)可以呈现为单色图标或多色表情符号。

☺︎✈︎☢︎☣︎☘︎☠︎♻︎☄︎☂︎☃︎☹︎☮︎⚠︎⛱︎✌︎✂︎✍︎✏︎☯︎ℹ︎♠︎♣︎⚖︎⚰︎✔︎➡︎

这取决于操作系统、浏览器和字体。如果您没有进行跨设备测试,您可能甚至不知道您的彩色表情符号在某些用户那里显示为简单的单色符号。

2. 国旗不包含在Segoe Emoji字体中。

Windows用户(除了使用Firefox浏览器的用户)将看到两个字母来表示国家,而不是国旗的表情符号。

3. 在旧操作系统(以及一些新操作系统上)缺少表情符号

每年,Unicode都会添加新的表情符号。在较旧操作系统上的人将无法使用这些更新。

以下是一些较新的表情符号在 macOS Ventura上正确呈现的样子:

Windows 10上,它们看起来是这样的:
Windows 10上,表情符号呈方块状,带有黑色轮廓,根本不显示表情符号

这不仅仅是传统技术的问题。一些当前的操作系统,特别是Windows 11,在更新系统表情符号方面也落后了。

解决方案

font-variant-emoji解决问题1

明确将字体系列设置为表情符号字体通常足以解决此问题。理想情况下,我们应该能够使用font-family: emoji。就像我们有font-family: system-ui来指定系统字体一样,这是指定系统表情符号字体的等效方式。

font-family: emoji大致相当于:

1
2
3
p {
font-family: Apple Color Emoji, "Segoe UI Emoji", "Noto Color Emoji";
}

font-family: emoji将永远保持最新。相比之下,通过使用命名字体,如果苹果、谷歌或微软设计了一个带有不同名称的全新表情符号字体,上述代码不生效。目前还没有浏览器发布了font-family: emoji,因此我们将不得不列出每个操作系统的不同字体(以及FirefoxWindows上使用的“Twemoji Mozilla”字体):

1
2
3
h1 {
font-family: "Twemoji Mozilla", Apple Color Emoji, "Segoe UI Emoji", "Noto Color Emoji", "EmojiOne Color";
}

如果您的文本既包含表情符号又包含常规文本,情况会变得更加复杂。假设您有以下代码:

1
<h1 style="font-family: 'Comic Sans MS', Apple Color Emoji, 'Segoe UI Emoji', 'Noto Color Emoji';">I ♥ emoji</h1>

Chrome首先会在Comic Sans字体中查找与♥相对应的字形。它找不到,所以它会查找我们列出的其他字体,并使用用户系统中的任何表情符号字体。我们在这里很幸运,因为Comic Sans字体不包含此表情符号。问题是,一些设计用于常规文本的字体确实包含我们试图避免的黑色伪表情符号。例如,在Mac上,系统字体包含一个黑色心形符号。

1
<h1 style="font-family: system-ui, Apple Color Emoji, 'Segoe UI Emoji', 'Noto Color Emoji';">I ♥ emoji</h1>

Chrome首先会在SF ProMac上的系统字体)中查找与♥相对应的字形,它会找到,因此代码不会呈现彩色表情符号。

除了设置字体外,您还应该在表情符号后附加变体选择器 &#xFE0F;

1
<h1>I ♥&#xFE0F; emoji</h1>

如果您想要单色版本,请附加 &#xFE0E;

1
<h1>I ♥&#xFE0E; emoji</h1>

仅使用变体选择器并不总是足以呈现您想要的内容。在一些浏览器中,特别是Chrome中,您的字体堆栈仍然可能会影响结果。

如果您使用大量表情符号,不断使用变体选择器会显得相当冗长。有一个即将推出的新CSS属性将使此操作更加简单。

1
2
3
h1 {
font-variant-emoji: emoji;
}

如果您使用的浏览器支持font-variant-emoji CSS属性,这个CodePen应该看起来像这样(第二行设置为font-variant-emoji: emoji):

您还可以使用font-variant-emoji: text,如果您想要单色版本。

使用彩色字体解决问题2(和3?)

苹果彩色表情符号字体大小为189MB。苹果使用sbix,这是最庞大的彩色字体格式,用于他们的表情符号,这在一定程度上解释了的文件较大的原因。谷歌的Noto Emoji彩色字体包含3,664个表情符号,文件大小为23MB。每年都会添加新的表情符号。即使您使用COLRv1,一种现代彩色字体格式,它能显著减小文件大小,但提供一个包含所有表情符号的字体仍然不合理。由于有这么多字形,文件大小注定会很大。

一些表情符号很常见,而其他许多则很少使用(空中缆车🚡,不可饮用水🚱,班卓琴🪕,以及这个东西是什么〽️ …)。

如果您的@font-face表情符号字体不包含某些小众表情符号,浏览器将回退到使用系统表情符号字体,因此用户仍然会看到一个表情符号 —— 尽管可能是以不同的视觉风格绘制的。

子集化是解决问题2的一个很好的答案。如果您从字体中剥离所有其他字符,则仅包含国旗的彩色字体的大小并不那么大。

有几种开源彩色表情符号字体可供您自由使用:

  • 谷歌的 Noto Color
  • Adobe 的 Emoji One
  • 推特的 Twemoji
  • Mozilla 的 FxEmoji
  • 微软的Fluent Emoji(他们发布了 SVG ,但您需要自己将 SVG 打包成字体)。

除了Fluent外,它们都包含国家旗帜。

对于较旧操作系统上缺少的表情符号,没有一个很好的解决方案。您可以将彩色字体子集化,以仅包含较新的表情符号(并随着更多表情符号的出现进行更新……),但它们可能与用户系统中的其他表情符号在风格上不一致(这可能比没有更好)。在开源表情符号字体中,FxEmoji Emoji One多年来都没有更新过新的表情符号。相比之下,Noto Color 始终保持最新。

如果您想使用彩色字体,您有两个选择:

  • 使用 COLRv0 字体。
    这将在所有浏览器中工作。它是否可行取决于您要使用的表情符号。COLRv0 不支持渐变,只支持纯色。

  • 同时使用 COLRv1 字体和 OpenType-SVG 字体。
    Chrome 团队明确表示他们永远不会支持 OpenType-SVGSafari 目前没有打算实现 COLRv1。幸运的是,从 FontLab 中导出这两种格式非常简单。使用 CSS @font-face 同时提供两种格式也相当简单。下面的 JavaScript API 可以有条件地加载适当的版本。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    f (CSS.supports("font-tech(color-COLRv1)")) {
    const fontFile = new FontFace(
    "emojifont",
    "url(COLRv1emoji.woff2)"
    )
    document.fonts.add(fontFile);
    document.body.style.fontFamily = "emojifont";
    } else if (CSS.supports("font-tech(color-SVG)")) {
    const fontFile = new FontFace(
    "emojifont",
    "url(OpentypeSVGemoji.woff2)"
    )
    document.fonts.add(fontFile);
    document.body.style.fontFamily = "emojifont";
    }