表情符号(Emoji)在Web中的使用
大约从 1998 年(还是 1999)年开始有了 Emojis(表情符号) 之后,Emojis 就风靡一时,在一些聊天工具和Web应用上也受到广泛的使用。也就是说,它不再局限于用在聊天工具用来交流,还在 Web 页面或应用上使用也越来越多,在一些组件上的使用也更频繁。
就在最近,微软发布了全新的 3D 风格的表情符号(Emoji),这套 3D 风格的表情符号已经在 Flipgrid 上线,并将于今年晚些时候登录 Teams 和 Windows 系统,Yammer、Outlook 和其他平台将在明年推出:
对于日常用户来说,表情符号是很好的。它们很有趣,也很容易使用。对于Web开发者而言,想在 HTML、CSS 和 JavaScript 中使用表情符号,情况还是有点不同。在这篇文章中,我们就和大家一起探讨表情符号在 Web 上的使用。
Emoji的历史
在开始聊 Emoji 在 Web 中的使用之前,先简单地了解 Emoji的历史。下面这部分内容摘自 维基百科对 Eemoji 的介绍:
第一个 Emoji 是由 栗田穰崇 于1998年或1999年创造,他当于隶属于 NTT DoCoMo 公司 i-mode 移动互联平台的团队。第一套 Emoji 包括 172 个 12 x 12
像素的图标,设计的初衷是作为 i-mode 消息功能的一部分帮助促进电子通讯,并作为区别于其他业务的特色功能。然后在 1997 年, Nicolas Loufrani 注意到, ASCII 表情符号在移动技术中的使用正在增加,他开始尝试动画效果的笑脸表情,目的是使用纯标点符号设计一套与现有 ASCII 表情对应的彩色图标,以促进其在数位领域的使用。 Loufrani 由此创造了第一套图形化表情、并编译了在线表情符号词典,将这些符号分成不同类别,包括:经典类、情绪类、旗标类、庆贺类、娱乐类、体育类、天气类、动物类、饮食类、民族类、职业类、行星类、星座类、婴儿类等,这些设计最初于 1997 年在美国版权局注册,随后全套图标于 1998 年以 .gif
格式文件在网络上发布,成为科技行业中使用的第一套图形化表情符号:
2000年,Loufrani 创建的表情目录开始提供下载,用户开始可以从互联网上为手机下载 Loufrani 创建的表情目录,该目录编译了超过 1000 个笑脸表情符号入其 ASCII 版本。该目录在 2002 年由 Marabout 以《Dico Smileys》书籍形式出版本。2021年,表情符号公司 Smiley Company 开始向各家电信公司的手机提供 Loufrani 图形表情符号的授权下载,这些公司包括诺基亚、摩托罗拉、三星等。
如果你对 Emojis 历史感兴趣的话,还可以阅读:
- The Illustrated History of Emojis
- Emoji Timeline: A timeline of cultural and technical events in the history of emoji
- Emojis: The Complete History
究竟什么是表情符号
我们所知道的表情符号是一个个彩色图标。但其更准确的定义是:
表情符号是使用在网页或聊天中的形意符号。
大多数情况之下,表情符号给我们的印象就是 它们是传统意义上的图像(或图标),但它们并不是。它们更像是 字母 、 数字 、 标点符号 和 奇怪的符号 ,我们更倾向于把它们当作 文本 来处理。
现在,我们只需要知道表情符号是:
- 只是字符(字符串)
- 可以被选择,复制、粘贴,并且调整大小等
- 有一个更原始的数字表示,可以用相应的数字来描述表情符号
初步对表情符号有这些认识就OK了。现在我们开始看看表情符号在 Web 中的使用和所起的作用。
HTML 中的表情符号
要在 HTML 文档中使用表情符号,我们首要做的第一件事情就是把 HTML 文档的字符Unicode编码设置为 UTF-8
。这样做可以确保表情符号在你的用户可能使用的浏览器和设备上(客户终端)显示一致。做到这一点很简单,只需要在 <head>
中使用 <meta>
来指定字符Unicode编码:
<meta charset="UTF-8">
有了这个基础保障之后,我们可以通过下面两种方式把表情符号添加到 HTML 文档中:
- 在 HTML 中直接使用表情符号
- 在 HTML 中使用表情符号对应的原始Unicode码编码
先来看 在 HTML 中直接使用表情符号。
在 HTML 中直接使用表情符号
在 HTML 中直接使用表情符号其实很简单,可以从某个地方复制粘贴到 HTML 文档中。不过,我们需要一个应用或网站,允许你复制表情符号的原始字符形式。现在在互联网上这样的网站或应用很多,你在 Google 搜索框中输入 Emojis 的关键词可以搜索一大堆,比如:
我个人比较喜欢 Emojipedia ,可以在这个网站上直接搜索或浏览你想要找的任何表情符号。一旦找到了你要的表情符号,你就可以看到并复制该表情符号:
一旦你复制了它,只需要在你的标记中(HTML标签元素中)把它粘贴到它的预定目的地,即 把复制过来的表情符号当作 HTML 标签元素的内容(文本节点):
因为表情符号被视为 基于文本的内容,因此你可以在任何支持文本的地方粘贴它们。正如上图所示,你在浏览器中预览你的 HTML 文档时,一切都会正常。如果你使用浏览器开发者工具审核带有表情符号的 HTML也能正常显式:
嗯!就是这么简单!从另一个地方,复制粘贴过来就可以OK!
在 HTML 中使用表情符号对应的Unicode编码
如果有的环境之下直接复制粘贴过来的表情符号放置在 HTML 的标签元素中,浏览器客户端无法正常显示(即直接指定的表情符号不起作用)。我们可以换过一种方式来将表情符号放置到 HTML 的标签元素中。即 使用代表表情符号的Unicode编码,因为每一个表情符号都有自己对应的一个Unicode编码。如果你在使用 Emojipedia 获取表情符号,那么可以看到表情符号对应的Unicode编码(Emojipedia的 “Codepoints”):
或者点击上图红色框的链接部分,可以看到该表情符号更详细的信息:
对于“Girl”表情符号,其对应的Unicode编码是 U+1F467
。如果我们要在 HTML 中使用 U+1F467
对应的表情符号,需要对该Unicode编码做一些转换,使用 &#x
来替代 U+1F467
编码中的 U+
,即 U+1F467
更换成 👧
。我们只需要把这个代码(👧
)放到 HTML 标签元素中即可:
<h1>👧 Girl</h1>
当你使用浏览器浏览的时候,可以看到“Girl”表情符号正常显示出来。最终的效果是一样的,但相比之下,使用表情符号编码看起来很怪,甚至不知道代表是什么:
效果如下:
有的时候你可能在一些网站或应用上获取的表情符号,但没有对应的Unicode编码,那你就无法像上面这样在HTML中使用表情符号。不过我们可以借助 JavaScript 脚本来把表情符号的Unicode编码转译出来:
function emojiUnicode (emoji) {
var comp;
if (emoji.length === 1) {
comp = emoji.charCodeAt(0);
}
comp = (
(emoji.charCodeAt(0) - 0xD800) * 0x400
+ (emoji.charCodeAt(1) - 0xDC00) + 0x10000
);
if (comp < 0) {
comp = emoji.charCodeAt(0);
}
return comp.toString("16");
};
或者使用一些在线的转译工具:
有关于这方面更详细的介绍,可以阅读 Dmitri Pavlutin(@panzerdp) 的《What every JavaScript developer should know about Unicode》一文。
CSS 中的表情符号
在 CSS 中使用表情符号和在 HTML 中非常的相似,也可以直接使用表情符号或代表表情符号的Unicode编码。但不同的是,CSS 中使用表情符号是需要具备一定依赖条件的。众所周知,CSS 一般是用来设置元素样式的,但有一个特殊点,使用 content
也可以用来生成内容。
熟悉 CSS 的同学可能知道,在 CSS 中可以在伪元素::before
或 ::after
或标记伪元素 ::marker
中使用 content
来生成内容,比如:
h1::before {
content:"我是一位";
color: #90f;
}
h1::after {
content: "(^_^)!";
color: #f90;
}
h1::marker {
content: "#01:";
color: #09f;
}
我们可以把::before
、::after
和::marker
中content
的字符串文本直接替换成表情符号,比如:
除此之外,在 CSS 的content
中也可以像 HTML 中一样直接使用表情符号Unicode编码(Codepoint)。和 HTML 不同的是,表情符号Unicode编码中的 U+
替换成#&x
,而在 CSS 中将 U+
替换成 \0
。比如花的Unicode编码是 U+1F33A
,那么在 CSS 中我们可以用 \01F33A
来替代:
最终的效果如下:
除了我们熟悉的content
生成内容可以使用表情符号之外,在 CSS 的 @counter-style
中的 symbols
中也可以使用表情符号用来设置列表的标记:
来看一个真实的示例:
效果如下:
JavaScript 中的表情符号
在 JavaScript 中使用表情符号和HTML或CSS中使用表情符号是相同的。在 JavaScript 中我们可以动态创建 DOM,可以动态改变 DOM的内容,也可以动态修改元素伪元素的content
的值。比如我们在使用.innerText
、.innerHTML
和.textContent
动态创建内容(或元素)时,可以直接使用表情符号:
也可以把表情符号的Unicode编码当作String.fromCodePoint()
方法参数传进来。和 HTML、CSS 类似,在String.fromCodePoint()
中参数的Unicode编码需要把 U+
替换成 0x
,比如 U+1F970
替换成 0x1F970
:
divElement.textContent = String.fromCodePoint(0x1F970);
在JavaScript 中使用表情符号能做更多的事情,比如你有一个表情符号的数组,使用 JavaScript 就可以动态的生成这些表情符号,并插入到 Web中:
const ulElement = document.querySelector("ul");
let emojis = [
0x1f600, 0x1f604, 0x1f34a, 0x1f344, 0x1f37f, 0x1f363,
0x1f370, 0x1f355, 0x1f354, 0x1f35f, 0x1f6c0, 0x1f48e,
0x1f5fa, 0x23f0, 0x1f579, 0x1f4da, 0x1f431, 0x1f42a,
0x1f439, 0x1f424, 0x1f493, 0x1f49e, 0x1f970, 0x1f929
];
emojis.forEach((emoji) => {
const liElement = document.createElement("li");
liElement.textContent = String.fromCodePoint(emoji);
ulElement.append(liElement);
});
效果如下:
表情符号能用来做些什么?
前面我们花了一些时间了解了表情符号怎么运用于 Web 中(分别在 HTML、CSS 和 JavaScript)。那表情符号能用来做些什么呢?我将通过一些简单的示例来告诉大家,表情符号在 Web 中的基本使用。
列表标记
表情符号最常用的地方就是给列表选项或display
为list-item
元素设置列表项标记,可以在li
的::before
、::after
或 ::marker
的 content
中使用表情符号。比如:
另外在 @counter-style
的 symbols
也可以使用表情符号,来设置列表项标记:
表情符号切换器
@Natalya 在 Codepen 上使用 input[type="checkbox"]
和 label
的 for
属性构建一个纯CSS的切换器(Switch),更有意思的是,在input
的选中状态和非选状态显示不同的表情符号:
<!-- HTML -->
<!-- 表情符号切换器组件的容器,可以放置在任何地方,子元素都是平级 -->
<div class="emoji-toggle emoji-travel">
<!-- input选择框在最前面,然后使用 ~ 选择器,可以选择它之后的兄弟元素 -->
<input type="checkbox" id="toggle2" class="toggle">
<!-- 表情符运用在 emoji 的伪元素上 -->
<div class="emoji"></div>
<!-- 绝对定位,放置在切换器所有元素最上面 -->
<label for="toggle2" class="well"></label>
</div>
/* CSS */
.emoji-toggle {
position: relative;
}
.well {
cursor: pointer;
}
.toggle {
appearance: none;
background: transparent;
position: absolute;
width: 100%;
height: 100%;
cursor: pointer;
z-index: 100;
}
/* 选择框未选中状态:off */
.toggle ~.emoji:before {
content: "未选中状态表情符号";
position: absolute;
left: 0;
top: -15px;
font-size: 40px;
z-index: 1;
transition: 0.2s;
}
/* 选择框选中状态: on */
.toggle:checked ~.emoji:before {
content: "选中状态表情符号";
left: 100%;
margin-left: -1em;
}
表情符号在滑块上的使用
上面示例是表情符号和input[type="checkbox"]
以及label
结合在一起构建的切换器的效果。除此之外,我们还可以把表情符号和 input[type="range"]
结合起来使用。
比如,在不同的值显示不同的表情符号(类似一个评分系统),@Bennett Feely 的 Emoji Rating 就是这样的效果:
除了具体的值对应一个表情符号之外,还可以在一个范围内对应一个表情符号,比如 @George W. Park 构建的一个表情符号和滑块结合在一起的效果,会根据温度值的变化来更换表情符号:
你甚至可以结合 input[type="range"]
的 :in-range
和 :out-of-range
根据 min
和 max
的范围值来设置不同的表情符号,除了input[type="range"
] 之外,这种方式也以运用于input[type="number"]
上面。感兴趣的同学不妨一试。
Emoji Bar
我们甚至还可以制作表情符号的Bar,比如 @Steven Lei 和 @Ben Brookes 在 Codepen提供的两个Demo:
心形点赞动效
在《重新创建Twitter点赞动效》 向大家介绍了使用表情符号替代 CSS Sprites实现点赞动效。我们来看看怎么用表情符号实现这样的效果:
HTML结构很简单,一个<input type="checkbox">
和 label
(input
的id
是label
的for
值),并且有一个额外的标签元素,比如示例的<i>
,同时用data-icon
设置表情符号。会使用相关的伪元素来实现一些UI元素效果:
其中第三层和第四层都是使用径向渐变来绘制的:
.react:after,
.react i:after{
content:"";
--c1:radial-gradient(red 50%,#0000 60%);
--c2:radial-gradient(orange 50%,#0000 60%);
background:
var(--c1),var(--c1),var(--c1),var(--c1),
var(--c2),var(--c2),var(--c2),var(--c2);
background-size:calc(var(--r)/6) calc(var(--r)/6);
background-position:
calc(50% - var(--r)/2) calc(50% - var(--r)/2),
calc(50% + var(--r)/2) calc(50% - var(--r)/2),
calc(50% - var(--r)/2) calc(50% + var(--r)/2),
calc(50% + var(--r)/2) calc(50% + var(--r)/2),
calc(50% + 0px) calc(50% + var(--r)*0.707),
calc(50% + var(--r)*0.707) calc(50% + 0px),
calc(50% - var(--r)*0.707) calc(50% + 0px),
calc(50% + 0px) calc(50% - var(--r)*0.707);
background-repeat:no-repeat;
transform:scale(0);
}
.react i:after {
background-size:calc(var(--r)/8) calc(var(--r)/8);
transform:rotate(60deg) scale(0);
}
每一层有八个圆点(四个红色和四个橙色)组成一个圆形。这里运用了一点数学知识,即sin()
和cos()
的N*45deg
的值。并且使用transition
设置过渡效果。
.react i {
transition: transform 0.6s cubic-bezier(0.5, -12, 1, -12);
}
.react:hover {
transition: transform 0.25s cubic-bezier(0.5, 400, 0.5, -400);
}
input:checked + .react i {
transition: filter 0.5s 0.5s, transform 1s cubic-bezier(0, 26.67, 0.5, 26.67);
}
input:checked + .react:before {
transition: transform 0.5s, border-width 0.5s 0.5s;
}
input:checked + .react:after,
input:checked + .react i:after {
transition: transform 0.5s 0.5s, opacity 0.4s 0.9s, background-size 0.5s 0.9s;
}
示例中用了cubic-bezier()
函数来设置transition-timing-function
,如果你对这方面感兴趣的话,可以阅读 @Temani Afif 的《Advanced CSS Animation Using cubic-bezier()
》一文。
最终组合出来的效果如下:
基于上面的示例,我们只需要改变 HTML中<i>
的data-icon
可以快速复制出很多效果:
而且我们还可以改变自定义属性的值,可以更换更多不同的颜色:
这样就可以让表情符号背景和每个点的颜色都不一样:
最终效果如下:
注意,上面Demo中表情符号变成灰色,使用的是CSS滤镜的特性filter: grayscale(0);
,另外整个布局采用的是Grid布局。如果你对 CSS Grid布局感兴趣的话,可以阅读 图解CSS 系列 中的 CSS Grid 布局系列。
卡牌游戏
上面看到的大部分是 CSS 中使用表情符号的示例。我们来看一个JavaScript 对表情符号数组的处理的示例。这个示例来自 @kirupa,源码来可以在Github上阅读。这是一个 Koncentration 游戏,每张卡片上绑定了一个表情符号,具体的效果如下:
表情符号做鼠标形状
在 CSS 中我们可以使用cursor
属性来指定鼠标形状:
在cursor
的url()
我们除了可以指定鼠标形状的图片之外,还可以使用 SVG 作为 URI,并且还可以结合表情符号,比如:
效果如下:
注意,随着<svg>
中的<text>
中表情符号数量增加,需要随着调整width
的值。
使用 CSS 自定义属性构建表情符号定制器
Jokob Eriksen 在 Codepen 上写了一个很有趣的示例,用 CSS 自定义属性构建了 一个表情符号的定制器。可以选择肤色,头发这样的修改器来调整 表情符号。
核心代码:
#sa:checked ~ .emoji {--skin: '\1F3FB'; }
#sb:checked ~ .emoji {--skin: '\1F3FC'; }
#sc:checked ~ .emoji {--skin: '\1F3FD'; }
#sd:checked ~ .emoji {--skin: '\1F3FE'; }
#se:checked ~ .emoji {--skin: '\1F3FF'; }
#ha:checked ~ .emoji {--hair: '\1F9B0'; }
#hb:checked ~ .emoji {--hair: '\1F9B1'; }
#hc:checked ~ .emoji {--hair: '\1F9B2'; }
#hd:checked ~ .emoji {--hair: '\1F9B3'; }
#he:checked ~ .emoji {--hair: '\1F9B4'; }
.emoji.a:before {
content: '\1F469' var(--skin,'') '\200D' var(--hair,'');
}
.emoji.b:before {
content: '\1F468' var(--skin,'') '\200D' var(--hair,'');
}
最终效果如下:
另外,在@keyframes
中改变自定义属性的值,还可以制作类似下面这样的动画效果,每s
中显示不同的表情符号:
表情符号和可访问性
表情符号在 Web页面或应用上的使用越来越广泛,她可以帮助我们非常容易地沟通复杂的想法,也可以很好的让我们在一些即时通讯上表达自己的感情(或心情)。前面花了一些篇幅和大家探讨了如何在 Web 中使用表情符号,那话又说回来,对于很多用户他可以很好的理解表情符号,但我在想,屏幕阅读器是否可以很好识别出表情符号。为什么有这么一问呢?
那是因为,表情符号是一种表意文字(代表一种想法或概念的图片)。它与以前我们熟悉的图片(比如,.png
、.gif
、.jpg
等)不同,表情符号是用 Unicode 字符显示的。在 Web 上,这通常是使用 Unicode 字符的十六进制或十进制表示,比如:
<span>💓</span>
我们在浏览器中可以看得出来,它是一个心形表情符号。那要是在屏幕阅读器上是什么呢?不妨一试:
亲测在 iOS 的 Voiceover 会朗读出“跳动的爱心”。
我在这个基础上,继续添加了几个其他的表情符号:
Voiceover的效果如下:
注意,这两个示例都是使用了非语义的span
标签,如果把标签更换成语义化的HTML标签呢?
和我预期的效果是一致的。但需要提出的是,A11Y也类似浏览器,在一些辅助技术上也是有兼容性的,而且表情符号是也是一种概念图片,如果希望表情符号在所有终端(辅助技术)上有一个较好的效果,可以考虑使用 ARIA 相关的属性,类似模拟<img>
的使用。比如在标签上使用 role
的值为img
,并且使用aria-label
来描述表情符号,也可以使用aria-labelledby
和aria-describedby
等特性:
<span>💓</span>
<span role="img" aria-label="跳动的爱心">💓</span>
Web可访问性(A11Y)也是一门非常复杂的技术体系,而且表情符号在可访问性方面也是较为复杂的,如果你对这方面感兴趣的话,可以阅读:
- Emojis and accessibility: How to use them properly
- EMOJI AND ACCESSIBILITY
- Accessible Emoji, Tweaked
- Accessible emoji
- Accessible Images, Icons and Emojis
- Building an accessible emoji picker
如果你想探知Web可访问性(A11Y)更多的知识,可以阅读小站有关于 A11Y 系列的文章。
小结
在这篇文章主要和大家探讨的是表情符号在Web中的使用方式(HTML、CSS 和 JavaScript)以及使用场景。但表情符号是一种表意文本,他在不同的国度,不同的文化背景,不同的人群,不同的时候,即使是同一个表情符号所代表的意思也将会不一样。甚至一不小心,还会造成歧义,引起法律纠纷,所以在使用的时候还是要注意这些文化背景带来的不确定性。
如果我们抛开这些语言和环境以及文化相关的背景,只从技术成面来说的话,表情符号在Web中的使用还是较为简单的。事实上,在一些社交性的Web网站或应用,已经到处可见了。最后附上Socialmediapsychology.eu上的一张图,来描述"为什么我们喜欢表情符号?"来结束有关于表情符号相关的探讨:
最后希望大家喜欢这篇文章。