Unicode表情符号的颜色

84

现代浏览器可以包含 Emoji 字符,但如何将其设置为单色并选择颜色呢?

例如,这里有一些 Emoji 和一些常规(平面0)Unicode 符号。所有符号都应该是红色的,但只有普通符号呈现为红色。

Emoji color attempt

相关HTML + CSS代码:

<p>
  
</p>
<p>
  ♥★ℹ
</div>

p {
  font-size: 3em;
  color: red
}

以下任何答案都无法在Firefox和Edge中工作。 - phuclv
9个回答

192

是的,你可以给它们上色!

div {
  color: transparent;  
  text-shadow: 0 0 0 red;
}
<div></div>


5
好的!我把它转换成了一个堆栈片段。不幸的是,这只能制作轮廓图,因为没有真正的透明编码。例如,笑脸渲染与鬼脸相同。我们对此似乎无能为力。 - mahemoff
5
这是Mac专属的吗 :-P,因为它在Windows 10上(无论使用哪个浏览器)都无法正常工作。 - Šime Vidas
4
在Chrome 53中,轮廓线有效,是的。但在Firefox 49中无效(表情符号保持不变)。 - nylki
3
谢谢,@nylki。事实证明,在这个主题上有一个错误报告 - https://bugzilla.mozilla.org/show_bug.cgi?id=1128190,但由于某种原因被标记为已解决。我在那里添加了一个评论。让我们等待Mozilla的回复。 - Tigran
3
在火狐浏览器61.0.1版本(Ubuntu Linux系统)中,color: transparent样式不能起作用。所有普通文本都会变成透明的,但完整的彩色表情符号不受影响。 - Patrick Horn
显示剩余18条评论

52

并非每个表情符号都能以相同的方式工作。一些是旧的文本符号,现在具有(可选或默认的)彩色表示,而其他一些则明确地仅作为表情符号。这意味着一些Unicode码点应该有两种可能的表示形式,即文本表情符号。作者和用户应该能够表达他们更喜欢哪一个。目前,这通常使用否则不可见的变量选择器 U+FE0E(文本,VS-15)和U+FE0F(表情符号,VS-16)来完成,但已经提出了更高级别的解决方案(例如CSS)

文本样式的表情符号是单色的,应该显示在前景色中,即在CSS中使用currentcolor,就像任何其他字形一样。Unicode联盟提供了一个按样式分类的表情符号概述Beta版本)。您可以在HTML中附加&#xFE0E;,以选择带有“默认文本样式; 具有VSs”和“默认表情符号样式; 具有VSs”标签列中的任何内容的文本变体。但这并不包括示例表情符号和许多其他表情符号。

p {
  color: red; font-size: 3em; margin: 0;
  text-transform: text;           /* proposed */
  font-variant-emoji: text;       /* proposed */
  font-variant-color: monochrome; /* proposed */
  font-color: monochrome;         /* proposed */
  font-palette: dark;             /* drafted for CSS Fonts Level 4 */
}
p.hack {
  color: rgba(100%, 0%, 0%, 0);
  text-shadow: 0 0 0 red;
}
p.font {
  font-family: Emojione, Noto, Twemoji, Symbola;
}
@font-face { /* http://emojione.com/developers/ */
  font-family: Emojione;
  src: local("EmojiOne BW"), local("EmojiOne"), local("Emoji One"), 
       /*   https://cdn.rawgit.com/Ranks/emojione/master/assets/fonts/emojione-bw.otf – monochrome only, deprecated, removed
            https://cdn.rawgit.com/Ranks/emojione/master/assets/fonts/emojione-android.ttf – with hack
            https://cdn.rawgit.com/Ranks/emojione/master/assets/fonts/emojione-apple.ttf – with hack */
       url("https://cdn.rawgit.com/Ranks/emojione/master/assets/fonts/emojione-svg.woff2") format("woff2"),
       url("https://cdn.rawgit.com/Ranks/emojione/master/assets/fonts/emojione-svg.woff") format("woff"),
       url("https://cdn.rawgit.com/Ranks/emojione/master/assets/fonts/emojione-svg.otf") format("truetype");
}
@font-face { /* https://www.google.com/get/noto/#noto-emoji-zsye */
  font-family: Noto;
  src: local("Noto Emoji"), local("Noto Color Emoji"), local("Noto"), 
       url("https://cdn.rawgit.com/googlei18n/noto-emoji/master/fonts/NotoEmoji-Regular.ttf");
}
@font-face { /* https://github.com/eosrei/twemoji-color-font/releases */
  font-family: Twemoji;
  src: local("Twemoji");
}
@font-face { /* http://users.teilar.gr/~g1951d/ */
  font-family: Symbola;
  src: local("Symbola");
}
<p title="♥★ℹ without variation selectors">&#x1F418; &#x1F427; &#x1F43C; &#x2665; &#x2605; &#x2139; &#x1F480; &#x1F44C;</p>
<p title="♥★ℹ with text variation selector 15">&#x1F418;&#xFE0E; &#x1F427;&#xFE0E; &#x1F43C;&#xFE0E; &#x2665;&#xFE0E; &#x2605;&#xFE0E; &#x2139;&#xFE0E; &#x1F480;&#xFE0E; &#x1F44C;&#xFE0E;</p>
<p title="♥★ℹ with emoji variation selector 16">&#x1F418;&#xFE0F; &#x1F427;&#xFE0F; &#x1F43C;&#xFE0F; &#x2665;&#xFE0F; &#x2605;&#xFE0F; &#x2139;&#xFE0F; &#x1F480;&#xFE0F; &#x1F44C;&#xFE0F;</p>
<p title="♥★ℹ with `text-shadow` hack" class="hack">&#x1F418; &#x1F427; &#x1F43C; &#x2665; &#x2605; &#x2139; &#x1F480; &#x1F44C;</p>
<p title="♥★ℹ with custom font" class="font">&#x1F418; &#x1F427; &#x1F43C; &#x2665; &#x2605; &#x2139; &#x1F480; &#x1F44C;</p>

我添加了U+1F480 Skull和U+1F44C OK Hand Sign,因为它们的“眼睛”应该透过背景显示,并且我使用数字字符引用只是为了使代码更明显和更能抵御复制粘贴错误。

然而,有人提出可以将两个变量选择器应用于任何字符,这在大多数情况下没有影响。请注意,一些供应商,尤其是三星,已经为几个其他字符(默认)发布了表情符号字形goo.gl/a4yK6pgoo.gl/DqtHcc)。


1
文本变量选择器绝对是原问题的最佳答案! - Sygmoral
2
Unicode.org上的变量选择器文档链接似乎已经失效,尽管http://unicode.org/faq/vs.html现在是官方的常见问题解答页面。 - Ben XO
有人可以用SVG做这个吗? - RixTheTyrunt

33

最近我自己想做这个,使用了一些新的CSS效果,在Firefox和Edge上也可以正常工作。

使用滤镜,首先使用sepia(1)来使颜色规范化,然后饱和度增加以获得纯红色。如果你想要摆脱黑线,在应用其他滤镜之前使用contrast(0)将表情符号的对比度降低。之后只需使用hue-rotate()将颜色从红色旋转到你想要的任何颜色即可。请注意,因为我使用了十进制而不是百分比,所以值为100意味着10000%。

Hue偏移量从红色定义开始。我们很幸运,sepia大部分都是红色,所以该轮从0度开始非常完美。您可以使用RGB to HSL转换器计算所需的偏移量。我在这里找到了一个不错的用JavaScript编写的工具:https://web.archive.org/web/20180808220922/http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c

必须将色调值乘以360才能从该函数中获取所需的结果。例如,rgbToHsl(0,100,100)[0]*360。将返回180。由于没有红色,这将是期望的结果,您将与红色相隔180度。

正如Litherium和Crissov所指出的,还有文本表情符号。它们更适合使用转换,并且通常看起来也更好。但是,在对文本表情符号应用上述方法之前,必须首先对其应用invert(.5),因为函数需要某种阴影进行操作。因此,只需在每个公式开头添加invert(.5)即可使它们在所有浏览器上对所有代码点进行操作。

.a { /* Normalize colour to a primary red */
    filter: sepia(1) saturate(100);
}
.b { /* Less saturation so more features, shifted colour 90-degrees */
    filter: sepia(1) saturate(5)  hue-rotate(90deg);
}
.c { /* Remove black outlines if desired by removing contrast */
    filter: contrast(0) sepia(1) saturate(100) hue-rotate(180deg);
}
.d { /* Other shades possible by lowering brightness */
    filter: contrast(0) sepia(1) saturate(100) brightness(.05) hue-rotate(180deg);
}
.e { /* Weird possibilities with no colour normalization */
    filter: contrast(100) hue-rotate(180deg);
}
.ma { /* Invert to provide a gray shade to apply sepia*/
    filter: invert(.5) sepia(1) saturate(100);
}
div {
    font-size: 25px;
}
.emo > div::after {
    content: "⛄";
}
.mono > div::after {
    content: "\1F30D\FE0E\26C4\FE0E\1F60D\FE0E\1F431\FE0E";
}
<div class="emo">
    <div>-:</div>
    <div class="a">a:</div>
    <div class="b">b:</div>
    <div class="c">c:</div>
    <div class="d">d:</div>
    <div class="e">e:</div>
</div>
<span>Change the code point to text mode:</span>
<div class="mono">
    <div class="a">a:</div>
    <div class="ma">ma:</div>
</div>

更新: 现在在npm上有更新的软件包可以计算色调等内容。你不需要使用我之前链接的网站上的代码片段。这里有一个例子:https://dev59.com/22865IYBdhLWcg3wnPya#56082323


@Mas 很高兴能帮到你。由于这种技术需要使用CSS滤镜效果,请确保您想要支持的浏览器都得到了支持:https://caniuse.com/#search=filter 话虽如此,像Crissov所提到的那样通过附加Unicode FE0E来指定文本变体,然后应用text-shadow也是有效的。但是,如果您只想支持现代浏览器,则使用滤镜的方法可以让您使用表情符号格式,这在应用于动态文本时可能非常有用。 - ADJenks
看起来Edge现在也支持通过text-shadow对它们进行着色了...所以如果你只支持最新的浏览器,我想你可以忽略我在这里做的所有这些巫术。 - ADJenks

26
您可以使用纯色填充它们:

solid

p {
  font-size: 20px;
  color: transparent;
  text-shadow: 0 0 0 blue;
}
<p></p>
<p></p>
<p></p>

或者你可以勾勒它们:

outline

body {
  background: #fff;
}

p {
  margin: 0;
  color: transparent;
  text-shadow: 0 0 3px blue;
  font-size: 20px;
  position: relative;
}

p::before {
  content: attr(title);
  position: absolute;
  text-shadow: 0 0 0 #fff;
}
<p title=""></p>
<p title=""></p>
<p title=""></p>


我更愿意使用其他属性,例如name来作为大纲,这样当用户有表情符号时,它就不会显示在工具提示中。好答案! - Zach Saucier

19
如果您想在表情符号内保留细节,可以使用 filter: url(svg),其中的 url() 将会带有一个 SVG 滤镜

svg {
  display: none;
}

div {
  -webkit-filter: url(#red);
  filter: url(#red);
}
<svg>
  <filter id="red">
    <feColorMatrix type="matrix" values="
      1 0 0 0 0
      0 0 0 0 0
      0 0 0 0 0
      0 0 0 1 0" />
  </filter>
</svg>

<div></div>

feColorMatrix 可能一开始看起来有些令人畏惧,但实际上定义自己的颜色是很简单的。以下是代表红色的示例:
1 0 0 0 0 
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0 
如果你从上面的粗体值中获取数据,我们可以看到它们与RGBA颜色模式的关系:
1 - 红色   (r)
0 - 绿色 (g)
0 - 蓝色  (b)
1 - Alpha通道 (a)
在这里,每个颜色都与0到255之间的值相关联,被分为255。因此,如果您有绿色的颜色,其RGBA值为:
 R   G   B  A
(0, 255, 0, 1)
那么您的值将如下:
0/255   -> 0 (r)
255/255 -> 1 (g)
0/255   -> 0 (b)
1       -> 1 (a) - 不要除以255
因此,使用这些值在矩阵中,我们得到:
0 0 0 0 0 
0 1 0 0 0
0 0 0 0 0
0 0 0 1 0 
现在,您可以将其作为其他过滤器的一个附加项(或删除旧过滤器),并为其指定一个id,以便可以在css中引用它:filter: url(#filterID)
请参见下面的实现版本:

svg {
  display: none;
}

.red {
  -webkit-filter: url(#red);
  filter: url(#red);
}

.green {
  -webkit-filter: url(#green);
  filter: url(#green);
}
<svg>
  <filter id="red">
    <feColorMatrix type="matrix" values="
      1 0 0 0 0
      0 0 0 0 0
      0 0 0 0 0
      0 0 0 1 0" />
  </filter>
  
  <!--         \/ --- change id to be referenced within css -->
  <filter id="green">
    <feColorMatrix type="matrix" values="
      0 0 0 0 0
      0 1 0 0 0
      0 0 0 0 0
      0 0 0 1 0" />
  </filter>
</svg>

<div class="red"></div>
<div class="green"></div>

<feColorMatrix /> 颜色矩阵生成器:

为方便起见,我已经制作了一个feColorMatrix生成器,它允许您选择或输入颜色以及不透明度,并从该颜色生成一个feColorMatrix:

const colorPicker = document.getElementById("color-picker");
const alphaPicker = document.getElementById("alpha-picker");
const codeOutput = document.getElementById("code-output");
const alphaValue = document.getElementById("alpha-value");
const pickedFilter = document.getElementById("picked-filter");
let r=0, g=0, b=0, a=1;

const generateFeColorMatrix = () => `<feColorMatrix type="matrix" values="
  ${r} 0 0 0 0
  0 ${g} 0 0 0
  0 0 0 ${b} 0
  0 0 0 ${a} 0" 
/>
`;

const update = () => {
  const feColorMatrixStr = generateFeColorMatrix();
  codeOutput.textContent = feColorMatrixStr;
  pickedFilter.innerHTML = feColorMatrixStr;
}

colorPicker.addEventListener("input", (e) => {
  const hexparts = e.target.value.match(/(\w{1,2})/g);
  ([r,g,b] = hexparts.map(hex => (parseInt(hex, 16) / 255).toFixed(2))); 
  update();
});

alphaPicker.addEventListener("input", e => {
  a = e.target.value;
  alphaValue.textContent = a;
  update();
});
alphaValue.textContent = a;
svg {
  display: none;
}

#color-picker {
  float: right;
}

#code-output {
  background-color: #f6f6f6; 
}

#emojis {
  -webkit-filter: url(#picked-filter);
  filter: url(#picked-filter);
  font-size: 30px;
}
<input type="color" id="color-picker" />
<input type="range" id="alpha-picker" value="1" min="0" max="1" step="0.01"/><span id="alpha-value">1</span>
<pre id="code-output">
</pre>
<svg>
  <filter id="picked-filter"></filter>
</svg>
<p id="emojis"></p>

请注意,当前此解决方案的浏览器支持非常有限。要查看此功能支持的完整浏览器列表,请参见此处


9

一些代码点可以以文本形式(非图片形式)或表情符形式(图片形式)绘制。Unicode 描述了可以使用两个变量选择器之一来选择这两种形式: U+FE0E(VARIATION SELECTOR-15) 或U+FE0F(VARIATION SELECTOR-16)。在以非图片形式绘制时,CSS 属性 color 应该适用。

例如:

U+2603 (雪人) 绘制方式如下:☃

代码点序列 U+2603 U+FE0E 绘制方式如下:☃︎

代码点序列 U+2603 U+FE0F 绘制方式如下:☃️

更多信息以及参与这些变化序列的代码点的完整列表可以在http://unicode.org/emoji/charts/emoji-variants.html找到。

(请注意,不同的操作系统可能在使用裸代码点时选择不同的默认值。例如,在 macOS 和 iOS 中查看此帖子 - 上面的裸代码点看起来不同!)


如何使用代码点序列?☃ 显示了纯色的那个。如何显示彩色的那个? - Curtis
只需将这两个字符并排放置。 - Litherum

3

尼克·帕森斯(Nick Parsons)提供的SVG矩阵解决方案也可以使用data:方案转换为内联解决方案:

filter: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix color-interpolation-filters='sRGB' type='matrix' values='0 0 0 0 0  0 1 0 0 0  0 0 0 0 0  0 0 0 1 0'/></filter></svg>#f");

color-interpolation-filters='sRGB'自从一些浏览器使用了不同的默认颜色空间,因此出现了。

我还建议添加一个灰度过滤器,否则某些表情符号将失去对比度,如果使用纯色。

filter: grayscale(100%) url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix color-interpolation-filters='sRGB' type='matrix' values='0 0 0 0 0  0 1 0 0 0  0 0 0 0 0  0 0 0 1 0'/></filter></svg>#f");

灰度滤镜也可以由矩阵表示,并且可以被纳入SVG数据中。下面是一个比CSS更符合人类感知的示例:

filter: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix color-interpolation-filters='linearRGB' type='matrix' values='0.2126 0.7152 0.0722 0 0  0.2126 0.7152 0.0722 0 0  0.2126 0.7152 0.0722 0 0  0 0 0 1 0'/><feColorMatrix color-interpolation-filters='sRGB' type='matrix' values='0 0 0 0 0  0 1 0 0 0  0 0 0 0 0  0 0 0 1 0'/></filter></svg>#f");

最后,这里是一些生成矩阵的 PHP 代码,它可以根据给定的颜色(以 CSS 十六进制颜色代码输入)生成矩阵:
function matrixcolor($hex)
{
  list($r, $g, $b) = array_map(function($c) {return $c / 255 / 3;}, sscanf($hex, "#%02x%02x%02x"));
  return "$r $r $r 0 0  $g $g $g 0 0  $b $b $b 0 0";
}

function colormatrix($col)
{
  return "url(\"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix color-interpolation-filters='linearRGB' type='matrix' values='0.2126 0.7152 0.0722 0 0  0.2126 0.7152 0.0722 0 0  0.2126 0.7152 0.0722 0 0  0 0 0 1 0'/><feColorMatrix color-interpolation-filters='sRGB' type='matrix' values='".matrixcolor($col)."  0 0 0 1 0'/></filter></svg>#f\")";
}

2
由于 Emoji 相对较新,因此尚不支持原生样式设置。
解决方法是使用 Emoji 字体,例如 Twitter 的 Twemoji。然后可以像 Font Awesome 或本地 Unicode 一样设置其样式。

-3

如果你需要在CSS中使用伪元素before和after,你可以像这样进行操作

<span class="react-thumb-fly" title="Aimé">
   <button class="react-toggle-icon-thumb"></button>
</span>

然后为CSS编写这个

.react-toggle-icon-thumb {
  width: 20pt;
  height: 20pt;
  font-size: 30pt;
  position: relative;
  color: gray;
  cursor: pointer;
  border: none;
  background: transparent;
  margin-left: 0px;
  margin-right: 8px;
  top: -0px;
}
.react-toggle-icon-thumb:before, .react-toggle-icon-thumb:after {
  position: absolute;
  top: 0;
  left: 0;
  transition: all .3s ease-out;
  content: "";
  font-family: fontawesome;
  color: transparent;  
 text-shadow: 0 0 0 #3498db;
}

.react-toggle-icon-thumb:hover:before {
  transform: scale(1.2);
  animation: thumbs-up 2s linear infinite;
}

@keyframes thumbs-up {
 25% {
  transform: rotate(20deg);
 }
 50%, 100% {
   transform: rotate(5deg);
 }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接