背景
上周在工作中遇到一个历史遗留缺陷,在管理后台配置的emoji表情,在有些手机上,部分emoji图标显示成方框格子,这个问题要是放在平时比较忙碌的时候,随便找个理由就能把产品和测试糊弄过去,但上周工作不算饱和,工作不饱和的时候,人的求知欲就比较旺盛,于是决定探究一下。
这是后端接口返回的emoji编码:
json
{
"ret": 0,
"retmsg": "ok",
"retdata": {
"content": [
{
// ...
"momentText": "\uD83D\uDE43\uD83E\uDD17\uD83E\uDD10\uD83D\uDE1C\uD83D\uDE2A\uD83E\uDD12\uD83E\uDD12\uD83E\uDDB7\uD83E\uDDB5\uD83E\uDD1B\uD83D\uDC48\uD83E\uDD1A\uD83D\uDE40\uD83D\uDE48\uD83D\uDC47\uD83D\uDC9C\uD83D\uDC97\uD83E\uDDE1\uD83E\uDD0E\uD83D\uDCA2\uD83E\uDD4B\uD83C\uDFD3\uD83E\uDD4E\uD83C\uDF81\uD83C\uDFB6\uD83C\uDFB6\uD83C\uDFBC\uD83D\uDD14\uD83E\uDE93\uD83E\uDE79\uD83E\uDDEC♉♌\uD83D\uDEC4\uD83D\uDD1B\uD83D\uDFE0\uD83D\uDD34\uD83D\uDFE8\uD83D\uDD39\uD83C\uDE50\n天天好心情",
},
],
},
}
这是正常的显示:
这是部分emoji图标显示成方框的情形:
emoji的前世今生
1999年从日本的手机中诞生emoji,emoji这个词在日语里的含义是"绘文字"。 "绘"对应"e","文字"对应"moji"。第一版emoji大部分是表达天气、交通、科技的符号,而非表情。如今已经成为社交软件中不可缺少的存在。emoji从诞生之日起就一直被一个问题所困扰,在不同的平台,同样的表情,展示效果看起来并不一样,没有标准化与统一化。不同的平台都根据本平台的审美来重新解读与设计 emoji 表情。苹果的设计风格特征是立体,渐变和阴影的细节比较考究;Google 则是更加轻松和卡通化; 微软喜欢又黑又粗的边框,可能是想与文字明显区分开来;Facebook(现在的Meta)的emoji表情表现力比较强,Twitter的emoji非常简洁,基本没有阴影渐变这些细节。如下图所示,同样一个翻白眼的表情,在每个平台看起来差别还是比较明显的。
emoji与unicode的关系
每一个 emoji,就是一个 Unicode 字符。全世界的 emoji 都由统一码联盟(The Unicode Consortium)来投票选拔和公布,世界各地的人们可以向联盟提交 emoji 提案。而统一码联盟的 emoji 规范,只是定义了某个字符的语义,再由 Emojipedia这个网站对 emoji 进行描述表达,最后允许大家按照对描述的理解,自由地去设计图案。
从2010年开始,Unicode 开始为 Emoji 分配码点。比如:U+1F4C5,U+1F468, U+1F600
等。 Unicode 只是规定了 Emoji 的码点和含义,并没有规定它的外观展示。举例来说,码点U+1F600表示一张微笑的脸,但是这张微笑的脸表情长什么样,则由各个平台(Windows,Mac,Linux, IOS, Android等)自己实现。如果用户的系统没有实现这个Emoji符号,用户就会看到一个没有内容的方框(如下图所示,三者必居其一,不光是emoji表情,其它类型的字体图标渲染不出来的时候也是这样的展示),因为系统无法渲染这个码点。
所以在PC端展示正常的emoji表情,在低版本的Android或IOS系统上,可能展示不太正常。
着手解决
知道了emoji表情为什么显示不出来的原因,解决方案也就水落石出。
- 下载emoji字体到自己的应用中 从网络下载所需的emoji表情字体,这样就可以摆脱对平台emoji字体的依赖。(靠谱)
- 升级操作系统 新版本的操作系统通常会包含更完整的emoji表情支持。(代价高)
- 替换为图片 即使表情显示不正常,也可以将emoji表情替换为等效的图片来表示。(说易行难)。
- 安装emoji表情包 有些手机厂商会提供额外的emoji表情包用于扩展默认的表情集。可以在应用商店搜索并安装适用于手机的emoji表情包。(不通用)
这里选择了可行性比较强的第一种方案,解决部分emoji表情在低版本手机上无法显示的问题。出现问题项目是个H5应用,所以采用Web开发技术中的css自定义字体解决这个问题。使用@font-face自定义字体时,通常需要加载好几种字体格式,以前不是很清楚这几种字体格式的区别,趁着这次机会,刚好梳理一下这一块。
常见的字体类型
常见的字体类型如下表所示,目前现代浏览器基本都支持.ttf
、otf
、woff
,.woff2
,.svg
字体格式,如果为了保证兼容不同的浏览器,一般会同时指定多个格式
字体类型 | 说明 |
---|---|
.ttf |
True Type,是Windows和Mac系统最常用的字体格式,它可以任意缩放和旋转不会出现锯齿,随着 windows 的流行,已经变成最常用的一种字体文件表示方式,这种格式的字体文件体积比较大,字体文件可以达到 24MB+,通常只用作安装到计算机中的字体,或者在网页中设备不支持 WOFF2 字体情况的兜底处理。 |
.otf |
Open Type,是可缩放性的电脑字体类型,是微软与Adobe共同开发用来替代TrueType的新字形,微软的IE浏览器全部采用这种字体。致力于替代TrueType字体。OTF 字体文件体积也很大,基本和 TTF 差不多。 |
.eot |
Embedded Open Type,微软开发的嵌入字体格式,允许OpenType字体用@font-face嵌入到网页并下载至浏览器渲染,存储在临时安装文件夹下。 |
.woff |
Web Open Font Format,专门为了We设计的字体格式标准,是对True Type、Open Type等字体格式的封装,体积非常小 |
.woff2 |
WOFF 1.0使用zlib压缩,文件大小一般比TTF小40%。而WOFF 2.0使用Brotli压缩,文件大小比上一版小30%。 |
.svg |
Scalable Vector Graphics Fonts,使用SVG来呈现字体(.svgz 是使用了Gzip压缩的SVG字体,这种字体是非常早期的标准,已经不推荐使用。) |
由于笔者的手机系统是Android,所以需要下载的字体是Noto Color Emoji
字体, 点击这里下载。下载的时候有一点要注意,你需要下载的是Noto Color Emoji
而非Noto Emoji
, 这两者的区别是前者的emoji图标是彩色的,图标很全面,当然emoji字体资源文件体积也比较大,接近24M,后者的emoji图标显示的是黑色,图标也不全。笔者刚开始下载的是Noto Emoji
字体,发现emoji依旧不显示,经过一番排查,才发现要下载的emoji字体文件的名称应该是Noto Color Emoji
。
另外大家有没有发现一个问题,就是ttf的文件体积很大,会造成页面加载资源比较卡顿,需要对ttf文件进行压缩,可以采用在线压缩工具,也可以采用命令行工具(font-spider,fontforge等),因为woff2格式的字体体积比较小,所以在网页端使用的话,一般使用的都是woff或者woff2格式。
测试demo代码文件内容如下:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>emoji显示测试</title>
<script src="http://cdn.staticfile.org/jquery/2.1.0/jquery.min.js"></script>
<style>
@font-face {
font-family: emoji;
src: url("./NotoColorEmoji-Regular.woff2") format('woff2');
}
.emoji {
font-family: emoji;
}
</style>
</head>
<body>
<pre class="emoji"></pre>
<script>
const momentText = "\uD83D\uDE43\uD83E\uDD17\uD83E\uDD10\uD83D\uDE1C\uD83D\uDE2A\uD83E\uDD12\uD83E\uDD12\uD83E\uDDB7\uD83E\uDDB5\uD83E\uDD1B\uD83D\uDC48\uD83E\uDD1A\uD83D\uDE40\uD83D\uDE48\uD83D\uDC47\uD83D\uDC9C\uD83D\uDC97\uD83E\uDDE1\uD83E\uDD0E\uD83D\uDCA2\uD83E\uDD4B\uD83C\uDFD3\uD83E\uDD4E\uD83C\uDF81\uD83C\uDFB6\uD83C\uDFB6\uD83C\uDFBC\uD83D\uDD14\uD83E\uDE93\uD83E\uDE79\uD83E\uDDEC♉♌\uD83D\uDEC4\uD83D\uDD1B\uD83D\uDFE0\uD83D\uDD34\uD83D\uDFE8\uD83D\uDD39\uD83C\uDE50\n天天好心情";
</script>
</body>
</html>
用VScode中的Live Server
扩展启动这个页面,在手机上打开,在如下图所示,原来不能显示的emoji表情已经可以正常显示了。