Предположим, вы захотели приукрасить в 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 страны, обычно криво и неказисто.


Источник: 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! ??

Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (28)


  1. enamchuk
    09.02.2025 11:05

    В Edge от Microsoft, ожидаемо, такая же проблема.


  1. vanxant
    09.02.2025 11:05

    Казалось бы, а можно было просто оставить флаги стран-участниц ООН...


    1. zelenin
      09.02.2025 11:05

      членство в ООН не решает вопросы признания


      1. vanxant
        09.02.2025 11:05

        Нууу, нет. Членство в ООН это признание мировым сообществом. Единичные голоса "против" это уже проблема этих голосов.


        1. zelenin
          09.02.2025 11:05

          Единичные голоса "против" это уже проблема этих голосов

          вам хватило одного комментария, чтобы забыть, что статья именно об этом

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


        1. Garrrry
          09.02.2025 11:05

          Microsoft американская компания,
          причём тут какойто оон?
          у неё другое в приоритете


  1. me21
    09.02.2025 11:05

    В дефолтном браузере на телефоне Хуавей тайваньский флаг не показывает, а палестинский — пожалуйста :)


    1. Phoenix678
      09.02.2025 11:05

      Весьма справедливо со стороны китайцев. :)


  1. Self_Perfection
    09.02.2025 11:05

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

    Пруфов бы. А так звучит правдоподобно, но может оказаться чьими-то домыслами, которые автор принял за истину.

    ЗЫ: я похоже от этого бага пострадал, угрохав недавно ненароком почти час пытаясь понять, почему Anytype на одном компьютере флаги стран не показывает.


    1. nixtonixto
      09.02.2025 11:05

      В Беларуси за публичную демонстрацию флага, под которым действующий глава страны давал свою первую присягу, можно гарантированно получить от 15 суток.


    1. dartraiden
      09.02.2025 11:05

      Доказательств нет, но, например, неофициальный обходной путь майки сломали. Может, случайно, т.к. такой сценарий в тестах не учитывают, может, и неслучайно.

      https://github.com/perguto/Country-Flag-Emojis-for-Windows


  1. czz
    09.02.2025 11:05

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

    Не используйте флаги для обозначения языков.


    1. achekalin
      09.02.2025 11:05

      Пошел в комменты, чтобы именно это написать. И так уже для английского языка сплошь и рядом флаг США используют (а как иначе, американцы не найдут же!), но бывает и наоборот - сайт реально предлагает язык (не локаль системы, а язык сайта!) и английский, и американский. Язык сайта при этом, ожидаемо, не меняется, хотя и должен бы (по сути, ам различий хватает), просто сделано, чтобы юзеры не тупили.


    1. grafdezimal
      09.02.2025 11:05

      Сначала хотел горячо поддержать, ведь действительно мы же про язык а не страну. В United Kingdom (флаг) Английский вообще не государственный язык, если уж совсем точно брать.

      Но всё таки флаг воспринимается визуально быстрее и проще, название языка надо бы писать на этом самом языке… или на сейчас выбранном языке? Или на обоих и ещё на Английском? German/Deutsch/немецкий довольно громоздко… Хотел было, значить, возразить… Но спросил себя, а в Австрии, интересно, тоже флаг ФРГ используют для обозначения немецкого на страницах… Мимм…

      Наверное лучше ISO 639. Да. Лаконичный de/deu/ger/нем… да блин…


      1. numark
        09.02.2025 11:05

        Обычно пишут на том языке, на который произойдет переключение. Иногда ещё добавляют на английском. Типа такого:

        Скрытый текст


    1. RomanPyr
      09.02.2025 11:05

      Не "языков", а "национальных языков". Важный момент, т.к. на территории СНГ некоторые национальные языки меняли алфавит с кириллицы на латиницу.

      И, согласитесь, есть разница в выборе "языка сайта": читать латиницу или кириллицу.

      Соответственно, там где "национальный", там и флаг соответствующей Нации.


    1. vlivyur
      09.02.2025 11:05

      А какая альтернатива этому?
      Вот заходишь ты на китайский сайт с иероглифами.Китайского,естественно,не знаешь.Сайт такой добрый,что позволяет переключиться на русский.Но всё написано иероглифами.И что из иероглифов является переключателем-хз,какой из выпавших пунктов русский язык-такой же хз


      1. M-M-I
        09.02.2025 11:05

        Значок земного шарика в углу сайта, а там выпадающий список English/Русский/Deutche и т.д. как вариант?


  1. VerityFreedom
    09.02.2025 11:05

    Давно есть решение проблемы (не слишком популярное):
    perguto/Country-Flag-Emojis-for-Windows: Get all country flag emojis to display properly on Windows, as well as generally better Google Emojis!


    1. Mayurifag
      09.02.2025 11:05

      Автор намекает частью заголовка «…NOT WORKING ANYMORE…» на то, что можно поискать альтернативные решения, для меня нашлось там же в Issues: https://github.com/perguto/Country-Flag-Emojis-for-Windows/issues/11 — просто установил и перезапустил браузер


  1. Globulopolis
    09.02.2025 11:05

    В шрифте Twemoji не все эмодзи есть, т.к. обновляется редко. Есть Noto Emoji в котором и готовые шрифты есть и png и svg.


  1. funca
    09.02.2025 11:05

    В Unicode есть Regional Indicator symbols, которые предназначены для отображения двухбуквенных кодов стран по стандарту ISO 3166-1 (EN, RU, US, и т.п.). В некоторых шрифтах вместо букв могут отображаться флаги этих государств. Но это опция, а не требование.

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

    Например, на русском языке говорят во многих странах. Поэтому отображение флага РФ в переключателе раскладки клавиатуры все время вызывало неоднозначность. Но до определённого момента тот факт, что язык и страна это разные вещи, волновал только теоретиков.

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


  1. CitizenOfDreams
    09.02.2025 11:05

    В идеальном мире эта проблема была бы однажды исправлена

    В идеальном мире просто не было бы семи тысяч языков и двух сотен срущихся между собой стран. (Да и Chrome под Windows, наверное, тоже бы не было.)


    1. allter
      09.02.2025 11:05

      Странно, что вы написали этот комментарий не на латыни, французском, английском или эсперанто, смотря какой идеальный мир вы для себя видите.


  1. Beholder
    09.02.2025 11:05

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

    А потом удивляемся, чего это так сайты тормозят... А они рисуют и делают там что хотят втихаря... Вот стоило оно того?

    Кстати, а память почистить не надо, удалив canvas и контекст от него?


    1. Beholder
      09.02.2025 11:05

      Кстати, если в canvas каким-то чудесным образом включится subpixel rendering, вы можете получить цвета на в целом чёрно-белом изображении.


  1. zzzzzzzzzzzz
    09.02.2025 11:05

    То есть, флаг может быть воспринят как политическая позиция, а вот буквенный код той же страны - это совсем другое?

    Ясно, понятно...


  1. numark
    09.02.2025 11:05

    Еще из интересного - встроенный API Android для определения кода (ISO 3166) страны по координатам ничего не покажет для интересных мест типа Абхазии, Палестины, Косово или (о боже!) полуострова Крым.

    Ну это, хотя бы, логично.