如何防止 Unicode 字符从 JavaScript 呈现为 HTML 中的表情符号?

我正在为 文件格式,信息搜索中的特殊字符寻找 Unicode。

有些字符呈现为经典的黑白字形,例如 something (警告标志,\u26A0⚠)。这些更可取,因为我可以对它们应用 CSS 样式(比如颜色)。

image of warning glyph

另一些则被渲染成较新的卡通表情符号,例如 something (沙漏,\u231B⌛)。这些都不是最好的,因为我不能完全风格他们。

image of hourglass emoji

看起来浏览器正在做这个改变,因为我能够在 Mac Firefox 上看到沙漏图形,只是不是 Mac Chrome 或 Mac Safari。

有没有办法迫使浏览器显示较旧的(单调的)版本?

更新 : 看起来(从下面的评论)有一个 文本表示形式选择器FE0E,可用于强制文本 vs 表情符号。选择器被串联为字符代码中没有空格的后缀,比如 HTML 十六进制的 ⌛︎或者 JS 的 \u231B\uFE0E。但是,不是所有的浏览器都支持它(如 Chrome 和 Edge)。

90121 次浏览

我不知道有什么办法可以关闭表情符号类型的渲染。通常我使用图标字体,如 字体酷毙了象形文字(自带 Bootstrap 3)。

使用这些字符而不使用 unicode 字符的好处是

  1. 你可以选择许多不同的风格,使它适合你的网站设计;
  2. 它们在不同的浏览器中是一致的(如果你曾经尝试过使用 Unicode 星形字符,你会发现 IE 和其他浏览器有所不同) ;
  3. 而且,它们完全可以设计样式,就像您试图使用的 unicode 字符一样。

唯一的缺点是浏览器在查看您的页面时还要下载一样东西。

追加用于强制文本的 Unicode 变体选择器字符,VS15,︎
这迫使前一个字符被呈现为文本,而不是表情符号。

<p>🔒&#xFE0E;</p>

结果:

了解更多: 文本或表情符号的 Unicode 符号

我有一个 Unicode字符在 span::beforecontent,我有 spanfont-family设置为“ Segoe UI 符号”。但是 Chrome 使用“ Segoe UI Emoji”作为字体来渲染它。

然而,当我为 span::before而不仅仅是为 spanfont-family设置为“ Segoe UI 符号”明确地时,它就起作用了。

对于我在 OSX 上的解决方案是将 font-family 设置为 EmojiSymbols

以上的解决方案都不适用于“用于谷歌浏览器的表情符号”扩展。

因此,我为这个 Unicode字符制作了一个截图“带有选票的投票箱”(u + 2611) ,并用 php 添加为图片:

 $ballotBoxWithCheck='<img src="pics/U2611.png" style="height:11px;margin-bottom:-1px">'; # &#9745; or /U2611

enter image description here

见: https://spacetrace.org/man_card.php?tec_id=21&techname=multi-emp-vessel

Android 字体并不像你想象的那样丰富。 字体文件没有这些奇异的标志符号,而 Android 有一个没有标志符号的字符黑客。它们被图标取代。

因此,解决方案是整合网站与一个网络字体(woff)。 使用 FontForge 创建新的字体文件,并从免费的 serif TTF 中挑选所需的字形。每个符号都需要一千。生成 woff 文件。

准备简单的 CSS 来导入自定义字体系列。

Css:

@font-face {
font-family: 'Exotic Icons';
src: url('exotic-icons.woff') format('woff');
}


.exotic-symbol-font {
position: relative;
top: 1px;
display: inline-block;
font-family: 'Exotic Icons';
font-style: normal;
font-weight: normal;
line-height: 1;


-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

Html 文件:

<html>
<head>
<meta charset="utf-8">
<link href="style.css" rel="stylesheet"></head>
<title>Test custom glyphs</title>
</head>
<body>
<table>
<tr>
<td class="exotic-symbol-font">
😭 ☠ &#x2660; a  g
</td>
</tr>
</table>
</body>
</html>

Google Chrome,桌面版本75,似乎消除了它基于加载页面时遇到的第一个 Unicode 转义来呈现 Unicode 字符的方法的歧义。例如,当解析为页面源代码中的第一个 HTML Unicode 转义符,并且没有相应的表情符号时,似乎可以向 Chrome 澄清页面中包含的转义符不能被呈现为表情符号。

如果你主要关心的是强制单色显示,这样表情符号就不会从文本中脱颖而出,那么 CSS 过滤器,无论是单独使用还是与 Unicode 变化选择器组合使用,都可能是你想要的。

p.gscale {
-webkit-filter: grayscale(100%);
filter: grayscale(100%);
}
a {
color: #999;
-webkit-filter: grayscale(100%) sepia(100%) saturate(400%) hue-rotate(170deg);
filter: grayscale(100%) sepia(100%) saturate(400%) hue-rotate(170deg);
}
<p class="gscale">You've now got emoji display on 🔒lockdown🔒.</p>


<p>External Link: <a href="https://knowyourmeme.com/memes/party-hard">celebrate 🎉</a></p>

与变化选择器不同,表情符号如何呈现并不重要,因为 CSS 过滤器适用于所有内容。(我用它们来制作超链接上的灰度 PNG 格式的“链接类型”图标,这些图标已经被修改为指向 Wayback Machine。)

就是 注意警告。您不能在子元素中覆盖父元素的过滤器,因此这种技术不能用于对段落进行灰度化,然后对其中的链接重新着色。

... 但是,对于要将整个事件作为超链接或不允许其中包含丰富标记的情况,它仍然很有用。(例如标题和描述)

然而,除非 CSS 真正得到应用,否则这不会起作用,所以我将给出第二个选项,它在 <title>元素中比 Unicode 变体选择器更可靠(我正在看着你 GitHub)。我不喜欢浏览器标签上的假图标) :

如果您要将用户提供的字符串放入 <title>元素中,请过滤掉表情符号以及任何粗体/斜体/下划线/等标记。(是的,对于那些没有看到它的人来说,标准的确要求 <title>的内容是纯文本,除了与号转义和我测试的浏览器将所有标记解释为文本之外。)

我能想到的两种方法是:

  1. 直接使用手工维护的 正则表达式,它与最新版本的 Unicode 放置表情符号及其修饰符的区块相匹配。
  2. 重复通过字母簇和 弃掉任何包含公认的表情符号代码点。(一个字符集是一个基础字形加上所有的变音符和其他修饰符组成的可见字符。我链接到的例子使用 Python 的 regex 引擎进行标记,然后是数据库的 emoji包,但 Rust 是一个很好的例子,在这种语言中,通过像 unicode-segmentation这样的板条箱迭代字符集是快速而简单的。)

扩展到 Ssokolow 的回答,使用过滤器是很好的,至少使轮廓可见,而不是使用简单的字体,但是当你想使用一个特定的颜色时,将 RGB 颜色转换成一系列 CSS 过滤器是非常困难的。

一个更好的(尽管相当冗长)选项是使用 <feColorMatrix> SVG 过滤器。结合灰度过滤器和数据 URI 方案,您可以通过 RGB 和内联 CSS 表示颜色:

.violet {
color: white;
filter: grayscale(100%) url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix type='matrix' values='0.78 0 0 0 0  0 0.082 0 0 0  0 0 0.522 0 0  0 0 0 1 0'/></filter></svg>#f");
}

不幸的是,您不能使用数据(从属性或变量获取)来插入 URL,但是至少您不必从 RGB 计算 CSS 过滤器。

为了防止 iOS 显示表情符号,你可以使用 font-family: monospace,它默认为字形的文本变体,而不是表情符号变体:

<p>Normal character: ↩</p>
<p>Monospace character: <span style="font-family: monospace">↩</span></p>

其他的解决方案对我来说都不管用,但是我最终找到了一些借助于 CSS 把戏的解决方案。在我的用例中,我在每个标记头的末尾添加了一个链接符号,用于直接链接到文章中的章节,但是表情符号看起来有点让人分心。下面的代码允许我使表情符号看起来像一个普通的符号,然后切换回来看起来像一个表情符号时,悬停在哪一个是完美的我的用例。如果您只是想让图标看起来更像一个符号,只需将文本阴影十六进制颜色更改为 # 000,如第二个示例所示。

.direct-link {
color: transparent;
text-shadow: 0 0 #dbe2ec;
}


.direct-link:hover {
color: inherit;
}
<h3>Blog Subheading<a href='#' class="direct-link">🔗</a></h3>

   .direct-link {
color: transparent;
text-shadow: 0 0 #000;
}
    <h3>Blog Subheading<a href='#' class="direct-link">🔗</a></h3>

我对这个问题的具体看法

我的网站使用 something (黑色右指三角形)和 CSS 伪元素(::after::before)中的类似字符来指示列表中的当前项目。

在我的测试中,我总是使用 将三角形字符和变异选择器15放在一起。首先,我同时使用了来自 谷歌字体Webfont安装在设备上的字体,它们都应该包含这些字符的字形,但出于某种原因,这个假设肯定是错误的。我还尝试了谷歌字体的不同子集,但没有效果: 我的两个安卓设备与谷歌 Chrome 和三星互联网(Chromium)总是呈现表情符号,而不是文本字形。

我的解决办法

我的解决方案是下载 格努自由字体的最新 WOFF (我知道它包含这些字符的符号) ,将其包含在我的项目中,并使用 @font-face定义它:

@font-face {
font-family: "Free Sans";
src: url("/site/static/fonts/FreeFont/FreeSans.woff") format("woff");
}

然后,为我的伪元素设置样式:

span.current::after {
font-family: "Free Sans", $universal-font-family ! important;
}

讨论

我还不确定仅仅为这几个字符使用那种额外的786K 字体对性能的影响。如果这成为一个问题,它应该是可能的使用精简的自定义字体,只有这些字符代替。

如果没有其他的答案适合你,你可能在你的字体堆栈中有一个或多个这样的字体(就像我们的情况一样) :

  • Segoe UI 表情符号
  • 苹果色表情

如果我没记错的话,这些字体包含在许多常用的字体堆栈中,比如 Github 字体堆栈。