Почему именно в Chrome под Windows на сайтах не работают эмодзи флагов

в 9:01, , рубрики: chrome, css, Firefox, ruvds_перевод, UI, windows, баги, браузеры, Веб-разработка, Программирование

Почему именно в Chrome под Windows на сайтах не работают эмодзи флагов - 1


Предположим, вы захотели приукрасить в UI своего сайта опцию выбора страны/языка симпатичными эмодзи флагов. Превосходно! Это создаст дополнительный визуальный ориентир, который поможет пользователям быстро находить нужную страну, да и в целом это просто красиво.

Более того, вы даже можете легко реализовать динамическое определение иконок на основе кода региона:

// Смещение для корректировки кода ASCII каждого символа в строке кода ISO страны для определения соответствующего флага.
const EMOJI_CHARACTER_OFFSET = 127397;

const getEmojiForCountryCode = (countryCode: string) =>
  String.fromCodePoint(
    ...countryCode
      .toUpperCase()
      .split('')
      .map((char) => char.charCodeAt(0) + EMOJI_CHARACTER_OFFSET),
  );

// "en-US"
const currentLanguageCode = navigator.language;
// "US"
const currentCountryCode = currentLanguageCode.split("-")[1];
// "🇺🇸"
getEmojiForCountryCode(currentCountryCode);
// "🇫🇷"
getEmojiForCountryCode("FR");
// "🇸🇪"
getEmojiForCountryCode("SE");

Всё идёт шикарно!

Как вдруг…

Поступает баг-репорт

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

Как вам?

Быть может, эти люди работают на древних ПК или используют совсем дремучий браузер, не умеющий отрисовывать эмодзи?

Вовсе нет. После уточнения у пользователей дополнительной информации выясняется, что работают они в последней версии Chrome в Windows.

Что за чертовщина? В порыве отчаяния я обратился к ChatGPT. Без толку, как обычно.

После ещё некоторых усилий, которые уже казались чрезмерными, я таки нашёл ответ.

Оказывается, в беспокойстве, что факт признания существования определённых стран может быть воспринят как политическая позиция, в Microsoft решили на корню пресечь подобную возможность, просто не включив значки флагов стран в системный шрифт Windows.

Загадка разгадана! Только представьте, что ваш компьютер, *тревожный вздох*, смог бы показывать тайваньский 🇹🇼 или палестинский 🇵🇸 флаг… Ужас!

Похоже на решительный шаг со стороны компании, хотя у него нет весомых документальных подтверждений — в основном это просто доводы озадаченных людей вроде меня, которые постят вопросы на StackOverflow, пытаясь понять, в чём проблема.

Хорошо, а как же тогда Windows обрабатывает эмодзи флагов? Элементарно! Система просто отрисовывает буквы из кода ISO страны, обычно криво и неказисто.

Почему именно в Chrome под Windows на сайтах не работают эмодзи флагов - 2
Источник: Using emoji on the web — Fully Stacked

Глядя на картинку выше, вы могли подметить, что у Firefox в Windows этой проблемы нет. Всё потому, что в Mozilla пошли на продуманный ход, дополнив браузер собственными эмодзи флагов.

Почему бы и команде Chrome не поступить также?

…Мы пока не планируем дополнять браузер собственным шрифтом с эмодзи, и этот баг отмечен как WontFix. В качестве альтернативного решения интересующий вас сайт может загрузить свой шрифт эмодзи с этими флагами. — сотрудник Google, 21 мая 2021 года

Что ж. Ладно.

Правда, у меня такая позиция Google вызывает двоякое впечатление. С одной стороны, я уважаю упрямый отказ латать недочёты другой компании.

С другой же, в Firefox с этой задачей справились без особых хлопот, а ведь Chrome под Windows использует огромное число людей, которые вынуждены смириться с последствиями этого решения Google.

В итоге такое положение дел затрудняет работу программистов, которым приходится учитывать этот «мусор», и портит пользовательский опыт, так как теперь для согласованной отрисовки флагов на всех устройствах JS-код должен определять, поддерживаются ли они, и скачивать дополнительные изображения/шрифты.

Что с этим можно сделать

Если вам прям очень нужны эмодзи флагов, есть два выхода:

▍ Замените живые эмодзи жёстко прописанными иконками или SVG-картинками

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

▍ Подставьте вместо эмодзи флагов кастомный шрифт

Добавление кастомного подменного шрифта станет неплохим решением. Нередко для этого используют Twemoji (именно его выбрали в Firefox), причём вы можете использовать в директиве @font-face CSS-свойство unicode-range, чтобы применить только часть шрифта, включающую недостающие эмодзи (хотя всё равно придётся скачивать весь файл шрифта размером 1,4 МБ).

@font-face {
  font-family: Twemoji;
  unicode-range: U+1F1E6-1F1FF, U+1F3F4, U+E0062-E0063, U+E0065, U+E0067, U+E006C, U+E006E, U+E0073-E0074, U+E0077, U+E007F;
  src: url("/fonts/twemoji.ttf") format("ttf");
}

:root {
  font-family: Twemoji, "My Main Font";
}

Я его не использовал, но подобный подход изящно реализует библиотека Country Flag Emoji Polyfill. Она использует JS-код для обнаружения поддержки эмодзи флагов стран и скачивает заполняющий пробелы шрифт только при необходимости. При этом в ней используется лишь часть шрифта Twemoji, включающая именно эмодзи флагов, что существенно уменьшает объём загрузки. Было бы здорово, если бы их код не опирался так сильно на жёстко прописанные адреса CDN, но такое решение станет неплохой отправной точкой.

К слову…

▍ Как программно определять поддержку эмодзи флагов стран?

Всё гораздо проще, чем может показаться: просто отрисовываем эмодзи на холсте и методом перебора определяем корректность отрисовки.

Лично я рисовал флаг США и затем перебирал пиксели в поиске такого, который содержит цвет не из оттенков серого. Суть в том, что в качестве замены для отсутствующих флагов Windows использует чёрно/белый текст. Поэтому, если только вы не отрисовываете флаг в оттенках серого, это позволит легко понять, отобразилась ли нужная цветная картинка.

export const getDoesBrowserSupportFlagEmojis = (): boolean => {
  const canvas = document.createElement('canvas');
  canvas.height = 1;
  canvas.width = 1;
  const ctx = canvas.getContext('2d');
  if (!ctx) {
    return false;
  }
  ctx.font = `${canvas.height}px sans-serif`;
  const flagEmoji = '🇺🇸';
  ctx.fillText(flagEmoji, 0, canvas.height);
  // Считываем пиксели холста и ищем те, которые содержат цвет вне оттенков серого. Здесь использован флаг США, так что в случае правильной отрисовки браузером должны обнаруживаться красные или синие цвета.     
 const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
  for (let i = 0; i < imageData.length; i += 4) {
    if (imageData[i + 3] === 0) {
      // Пропускаем прозрачные пиксели.
      continue;
    }
    if (imageData[i] !== imageData[i + 1] || imageData[i] !== imageData[i + 2]) {
      // Если все три цветовых канала совпадают, значит, пиксель содержит оттенок серого. Если хоть один пиксель не будет представлен оттенком серого, значит, браузер корректно отобразил эмодзи флага. В этом случае вернуть true.

      return true;
    }
  }

  return false;
};

В проекте, где мы столкнулись с описанной проблемой, было решено не заморачиваться с подменным текстом и просто полностью скрывать эмодзи при отсутствии их поддержки браузером. Печально, но жить можно.

Думаю, самый важный урок здесь в том, что эмодзи флагов не стоит делать неотъемлемой частью дизайна вашего сайта, в противном случае можно сильно пожалеть. В идеальном мире эта проблема была бы однажды исправлена, но мы не видим никаких движений в эту сторону уже несколько лет, так что я здесь без особых надежд.

Спасибо тебе, Microsoft! 🇹🇼

Автор: Bright_Translate

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js