Как не дать тек­сто­вым гли­фам пре­вра­тить­ся в эмод­жи

Перевод «Prevent text glyphs from turning into emojis»

Перевод Никита Дубко

Редактура Вадим Макеев

В прошлом году передо мной стояла интересная задача: сделать символ сердечка частью заголовка страницы. Мы организовывали конференцию «Я Люблю Фронтенд», а слово «Люблю» для большей эмоциональности хотели заменить символом сердечка.

Казалось бы, какие могут быть проблемы?

Если у вас есть заголовок «Я ❤ Фронтенд», он рендерится по-разному в разных браузерах в разных операционных системах. Например, на Android и iOS сердечко выглядит как эмоджи. И это огромная проблема, если вам нужно этот заголовок стилизовать.

Юникод Скопировать ссылку

Всё дело в рендеринге. Никита Прокопов описал этот нюанс в своей подробной статье про эмоджи.

Каждый символ, который вы используете, имеет свою UTF-8 последовательность, свой код. Например, английская буква A имеет код U+0041, буква Z — U+005A, символ $ — U+0024 и так далее. То же касается и эмоджи: ❤ имеет код U+2764.

Вы можете вставлять символы в свой HTML как Юникод-последовательность, а не готовыми символами.

<span>Я ❤ Фронтенд</span>
или
<span>Я &#x2764; Фронтенд</span>

&#x — префикс для указания Юникод-последовательности.

Но что делать, если текущий указанный шрифт не содержит внутри себя глифа, который может отрендерить ваш UTF-8 символ? Операционная система пытается найти любой шрифт, который содержит такой глиф. Для iOS это будет Apple Color Emoji, для Android — Noto Color Emoji. Но, кажется, мы можем контролировать этот процесс.

Шрифты Скопировать ссылку

Первое решение — иметь в наличии шрифт, который содержит все необходимые нам глифы. Например, Arial. Или какой-то кастомный шрифт. Вам нужно добавить его в фолбеки внутри CSS.

body {
    font-family: 'Text Font', 'Custom Glyphs Font', sans-serif;
}

Но мне не нравятся подобные решения, потому что у меня обычно нет полного контроля над всеми глифами в тексте. Особенно если разработка подразумевает какую-то админку для наполнения контентом. Больно пересобирать шрифт каждый раз, когда мне понадобится новый глиф.

Селекторы варианта начертания Скопировать ссылку

К счастью, есть другое решение. В UTF есть специальные символы для управления рендерингом — селекторы варианта начертания (англ. variation selectors). Символ U+FE0E просит ОС и браузер отрендерить предыдущий глиф в виде текста, а U+FE0F — в виде эмоджи.

Давайте попробуем.

<ul>
    <li>&#x2600; может отрендериться по-разному.</li>
    <li>&#x2600;&#xFE0F; должен выглядеть как эмоджи солнца.</li>
    <li>&#x2600;&#xFE0E; должен выглядеть как текстовый символ солнца.</li>
</ul>
  • ☀ может отрендериться по-разному.
  • ☀️ должен выглядеть как эмоджи солнца.
  • ☀︎ должен выглядеть как текстовый символ солнца.

Получается, если вам нужно выключить эмоджи в тексте, нужно сконвертировать выбранный символ в последовательность UTF-8 или UTF-16 (например, при помощи symbol.codePointAt(0).toString(16) в JS), потом добавить к этому символу &#xFE0E.

<span>Я &#x2764;&#xFE0E; Фронтенд</span>

И это всё не работает для эмоджи сердечка на Android. Я не знаю, почему. Когда мы тестировали это в прошлом году, всё было хорошо, но… Вы можете поиграть с различными символами в песочнице. Но как по мне, что-то лучше, чем ничего.

Доступность Скопировать ссылку

Помните, что все эмоджи имеют своё текстовое представление. Например, ⭐︎ — это «белая средняя звезда», ► — «чёрная стрелка, указывающая вправо». И скринридеры будут использовать эти тексты.

В итоге наш заголовок «Я ❤ Фронтенд» зачитывается утилитой VoiceOver как «Я Красное сердце Фронтенд». Кажется, это не то, что мы хотели сказать.

Чтобы починить это, используйте глифы правильно.

<span role="img" aria-label="Люблю">
    &#x2764;
</span>

Итоговый результат, который мы использовали на сайте конференции, ниже.

<h1>
    Я <span role="img" aria-label="Люблю">
        &#x2764;&#xFE0E;
    </span> Фронтенд!
</h1>

Источники Скопировать ссылку