Как устроены эмодзи: кодовые точки, тон кожи и квадраты
Почему эмодзи выглядят по-разному на каждом устройстве, как собраны тон кожи и составные символы и почему один смайлик весит семь символов.
Эмодзи — это символ. Такой же по природе, как буква «А», запятая или латинская q. Как только это укладывается в голове, странности перестают быть странностями: пустой квадрат вместо смайлика, сердечко, которое на чужом телефоне выглядит иначе, семья, распадающаяся на четырёх отдельных человечков. Инструмент Эмодзи копирует эти символы в буфер обмена, а дальше начинается вот что.
Никто не договорился, как выглядит 😀
Unicode задаёт номер. Картинку он не рисует. U+1F600 означает «улыбающееся лицо», и на этом спецификация заканчивается. Остальное решает тот, кто делал шрифт на вашем устройстве.
У Apple это Apple Color Emoji, у Android — Noto Color Emoji, в Windows — Segoe UI Emoji, который в обновлении до Windows 11 перерисовали в плоском стиле и этим многих разозлил. Twitter собрал собственный Twemoji, у WhatsApp свой набор. То есть, вставляя 😀 в сообщение, вы отправляете не картинку, а число 128512, и телефон собеседника рисует то, что считает нужным.
Отсюда история с пистолетом, который превратился в водяной. Apple заменила рисунок в 2016 году, остальные подтянулись к 2018-му, а сам символ при этом не менялся вообще.
Пустой квадрат
Квадрат или знак вопроса в ромбе означает, что в шрифте на принимающей стороне нет глифа для этой кодовой точки. Почти всегда дело в возрасте. 🫠 появился в Unicode 14.0 в сентябре 2021 года, поэтому всё, что выпущено раньше — Windows 10, Android, застрявший на одиннадцатой версии, браузер в телевизоре — рисовать его просто нечем.
Безопасная зона — символы из первой партии 2010 года и набора Emoji 1.0 2015-го: 😀, ❤️, 👍, 🔥. Если эмодзи уходит в систему, которую вы не контролируете (тема письма, пуш-уведомление, SMS-шлюз), берите тот, что постарше.
Тон кожи — это второй символ, приклеенный сзади
В 2015 году Unicode 8.0 добавил пять модификаторов на основе дерматологической шкалы Фитцпатрика: от U+1F3FB до U+1F3FF. Сами по себе они не эмодзи. Модификатор ставится сразу после базового символа, и шрифт склеивает пару в один глиф.
👍 (U+1F44D) вместе с U+1F3FD даёт 👍🏽. Две кодовые точки, одна картинка.
Модификатор принимают только эмодзи, где видна кожа: ладони, отдельные люди и профессии на их основе. У 🐶 его нет. У 👪 тоже, поэтому в списке для таких символов образцы тона не показываются.
Почему один смайлик весит семь символов
Вот здесь начинаются проблемы у всех, кто упирается в лимит.
Большинство эмодзи лежит за пределами базовой многоязычной плоскости, поэтому JavaScript хранит их как две единицы UTF-16. "😀".length вернёт 2, а не 1. С тоном кожи будет уже 4. А 👩💻 вообще не одиночный символ: это 👩, невидимый соединитель (U+200D) и 💻 — три кодовые точки и пять единиц.
Семья 👨👩👧👦 состоит из четырёх человек и трёх соединителей: семь кодовых точек, одиннадцать единиц UTF-16, одна картинка.
Та же арифметика объясняет, почему инвертор текста режет строку по кодовым точкам, а не по единицам UTF-16: наивный переворот разорвал бы 😀 пополам и вернул два бессмысленных суррогата вместо эмодзи.
X считает большинство эмодзи за 2 символа из лимита в 280. Описание профиля в Instagram, SMS-шлюзы и поля в базе данных считают каждый по-своему. Если лимит важен, проверьте готовый текст в счётчике символов, а не на глаз.
Тот же соединитель объясняет и распад символов. Стоит вырезать U+200D — а простые текстовые поля и старые SMS-системы делают это охотно — и 👩💻 превращается в 👩💻. Два эмодзи вместо одного, без всякого предупреждения. Одиночные символы так не ломаются, поэтому для непредсказуемого канала лучше взять 😀, а не 🧑🚀.
Если текст уходит в HTML и не хочется гадать про кодировку файла, прогоните символ через кодировщик HTML-мнемоник и вставьте 😀.
В остальных случаях откройте подборку эмодзи, наберите нужное слово, кликните один раз и вставьте.