Как отрисовка CJK-шрифтов раскрывает вашу реальную ОС в отпечатке
Семейства китайских, японских и корейских шрифтов, цепочки подстановки и метрики текста могут выдать хост-систему. Что отличается и что нужно для согласованного результата.
BotBrowser Team
Нужна поддерживаемая продуктовая документация?
У этой статьи есть соответствующая страница в центре документации. Используйте docs для каноничного сценария настройки, актуальных флагов и долгосрочной справки.
BotBrowser может согласовать набор и перечисление шрифтов авторизованного профиля для CJK-тестов, но не гарантирует принятие сайтом и не управляет его CSS, загрузкой шрифтов или сервером.
TL;DR
TL;DR: Доступность, подстановка и метрики CJK-шрифтов могут раскрыть хостовую ОС. BotBrowser может согласовать набор шрифтов профиля и перечисление для авторизованных тестов, но не гарантирует принятие идентичности сайтом и не управляет CSS страницы или её сервером.
Сравнение CJK-рендеринга на разных хостах показывает ограничения, которые остаются вне контроля BotBrowser.
Содержание
- Почему CJK-текст раскрывает хост-платформу
- Семейства CJK-шрифтов по платформам
- Цепочки подстановки и метрики текста
- Почему исправления на стороне хоста оставляют измеримый разрыв
- Выбор режима шрифтов для CJK-работы
- Проверка результата и границы возможностей
- Итог
Почему CJK-текст раскрывает хост-платформу
Китайский, японский и корейский текст позволяет странице быстро понять, в какой операционной системе на самом деле работает браузер. Каждая платформа поставляется со своими семействами CJK-шрифтов, подбирает отсутствующие шрифты по своей цепочке подстановки и рисует глифы собственным стеком отрисовки текста. Профиль, который выглядит согласованным для латинского текста, всё равно может показать хост-платформу, как только страница измерит или нарисует восточноазиатские символы.
Причина проста. Латинские шрифты вроде Arial или Helvetica есть на нескольких системах, поэтому список с ними мало что говорит. CJK-шрифты велики, привязаны к поставщику и устанавливаются в зависимости от языковых пакетов системы. Список с Microsoft YaHei указывает на Windows. Список с PingFang SC указывает на macOS. Список с Noto Sans CJK и WenQuanYi указывает на типичный рабочий стол или сервер Linux.
В разделах ниже разбирается, что раскрывает отрисовка CJK, почему привычные исправления на стороне хоста оставляют измеримый разрыв и что нужно для согласованного результата на разных платформах. Там же показано, как выбрать режим --bot-fonts для CJK-сценария и как проверить результат коротким сравнением ширины через Canvas. Более общую картину сигналов шрифтов вы найдёте в материале об отпечатках шрифтов и согласованности текста между платформами.
Семейства CJK-шрифтов по платформам
Списки ниже представляют собой типичные примеры, а не полные перечни. Реальные установки отличаются в зависимости от версии операционной системы, установленных языковых пакетов и шрифтов, добавленных пользователем или администратором. Используйте их, чтобы понять, какие семейства обычно относятся к какой платформе, а не как контрольный список, которому должна соответствовать каждая машина.
Windows обычно предоставляет такие CJK-семейства.
- Упрощённый китайский: Microsoft YaHei, SimSun, SimHei, FangSong, KaiTi, NSimSun
- Традиционный китайский: Microsoft JhengHei, MingLiU, PMingLiU
- Японский: Yu Gothic, Meiryo, MS Gothic, MS Mincho, MS PGothic
- Корейский: Malgun Gothic, Batang, Dotum, Gulim, Gungsuh
macOS обычно предоставляет такие CJK-семейства.
- Упрощённый китайский: PingFang SC, STHeiti, STSong, STKaiti, STFangsong
- Традиционный китайский: PingFang TC, PingFang HK, LiSong Pro
- Японский: Hiragino Sans, Hiragino Kaku Gothic, Hiragino Mincho
- Корейский: Apple SD Gothic Neo, AppleMyungjo, Nanum Gothic
Дистрибутивы Linux обычно предоставляют такие CJK-семейства, в зависимости от установленных пакетов.
- Все три языка: Noto Sans CJK (варианты SC, TC, JP и KR) и Noto Serif CJK
- Китайский: WenQuanYi Micro Hei, WenQuanYi Zen Hei
- Японский: IPAGothic, IPAMincho, Takao Gothic
- Корейский: UnBatang, UnDotum
Практический вывод состоит в наборе несоответствий, которые легко заметить с первого взгляда. Профиль, который заявляет Windows с китайской локалью, но не сообщает ни Microsoft YaHei, ни SimSun, непоследователен, потому что китайская установка Windows поставляет их по умолчанию. Профиль macOS для Японии без Hiragino Sans непоследователен так же. Машина Linux, сообщающая шрифты Windows рядом со шрифтами Apple, не соответствует ни одной реальной установке, поскольку эти семейства никогда не приходят от одного поставщика.
Регион важен и внутри китайского языка. Упрощённый китайский принят в материковом Китае, а традиционный используется на Тайване и в Гонконге, и на каждой платформе для них есть отдельные семейства, например PingFang SC в сравнении с PingFang TC и PingFang HK в macOS или Microsoft YaHei в сравнении с Microsoft JhengHei в Windows. Поэтому профиль, заявляющий тайваньскую локаль, должен содержать семейства традиционного китайского, а не только упрощённого.
Язык важен не меньше платформы. Машина Windows, настроенная на английский, может сообщать мало CJK-шрифтов, а машина, настроенная на китайский, сообщает много. По этой причине CJK-локаль, список CJK-шрифтов и заявленная операционная система должны совпадать. Если одного из трёх элементов нет или он указывает в другую сторону, сочетание выглядит необычно, даже когда каждое значение само по себе правдоподобно.
Цепочки подстановки и метрики текста
Когда страница запрашивает семейство шрифтов, которое не установлено, браузер не останавливается. Он проходит по цепочке подстановки, то есть по упорядоченному списку семейств, которые пробует, пока одно из них не покроет символы текста. Спецификация CSS Fonts описывает, как работают универсальные семейства и подстановка по символам, а каждая платформа наполняет эти механизмы собственными значениями по умолчанию. В итоге один и тот же CSS может приводить к разным шрифтам в разных системах.
Типичные цепочки подстановки для китайского выглядят так.
- В Windows китайский текст обычно получает Microsoft YaHei, а затем SimSun.
- В macOS он обычно получает PingFang SC, а затем STHeiti.
- В Linux он обычно получает семейство Noto Sans CJK или WenQuanYi, в зависимости от того, что установлено.
Авторы страниц обычно пишут стек шрифтов, например сначала семейство macOS, затем семейство Windows и в конце универсальное семейство. Браузер вычисляет стек слева направо для каждого символа и использует первое установленное семейство, которое покрывает этот символ. Поэтому порядок в собственном CSS страницы определяет, какое установленное семейство станет видимым, а стек, написанный для нескольких платформ, естественно даёт на каждой из них свой результат.
Представьте страницу, которая запрашивает font-family: "Nonexistent Font", sans-serif и показывает китайский текст. Ничто на странице не называет платформу, но итоговые глифы берутся из разного семейства в каждой системе, а вместе с ними меняются видимые формы и интервалы. Странице не нужен список установленных шрифтов, чтобы заметить разницу. Ей достаточно отрисовать текст и посмотреть на результат.
Язык текста добавляет ещё один слой. Китайский, японский и корейский делят множество иероглифов Han, но предпочтительные формы глифов зависят от языка. Браузеры используют заявленный язык содержимого и языковые настройки системы, чтобы выбирать между региональными вариантами. Локаль, заявляющая японский язык, при китайских формах глифов после подстановки становится ещё одним несоответствием, которого стоит избегать.
Помимо доступности, CJK-шрифты дают измеримые различия.
- Ширина глифов: отдельные символы, особенно в строках с латиницей и CJK вперемешку, имеют разную ширину продвижения в разных семействах.
- Высота строки: интервал между строками по умолчанию зависит от вертикальных метрик выбранного семейства.
- Правила интервалов: пунктуация, кернинг и расстояния между символами подчиняются разным соглашениям в китайской, японской и корейской типографике.
- Хинтинг и растеризация: попиксельный вид мелкого текста зависит от данных хинтинга шрифта и от DirectWrite в Windows, Core Text в macOS или FreeType в Linux.
Эти значения попадают в вёрстку. Вызовы вроде getBoundingClientRect() и getComputedStyle() возвращают числа, зависящие от фактически использованного шрифта, а measureText в Canvas возвращает ширину строки в текущем шрифте. MDN описывает measureText как способ получить метрики текста, поэтому он подходит и для простой проверки: если ширина строки меняется после указания семейства, семейство найдено, а если не меняется, браузер подставил другой шрифт.
Почему исправления на стороне хоста оставляют измеримый разрыв
Когда оператору нужен CJK-результат, отличающийся от хоста, обычно применяют три подхода. Каждый решает часть задачи и оставляет другую часть открытой. Понимание этого разрыва объясняет, почему согласованный результат требует выравнивать список шрифтов и итог отрисовки вместе.
Первый подход состоит в установке на хост CJK-шрифтов целевой платформы. На сервере Linux это может означать добавление базовых шрифтов Microsoft, CJK-пакетов или отдельных файлов шрифтов. Для некоторых страниц это работает, но имеет свою цену.
- Он меняет операционную систему, поэтому все экземпляры браузера на машине видят новые шрифты, а не только тот экземпляр, которому они нужны.
- Совместная установка семейств Windows и macOS даёт список, который не соответствует ни одной реальной платформе.
- Отрисовка по-прежнему проходит через текстовый стек хоста, например FreeType в Linux, а не через стек представляемой платформы.
- Поддержание одинаковых установленных шрифтов на многих серверах добавляет эксплуатационной работы и вопросов лицензирования.
Второй подход заключается во внедрении веб-шрифтов. Страница или скрипт добавляет шрифты через CSS, чтобы текст рисовался выбранным семейством. Это управляет видом части текста, но не меняет то, что сообщает система. Распространённый способ обнаружить шрифт состоит в том, чтобы измерить текст с этим семейством и без него и сравнить ширину. Внедрённый веб-шрифт может отрисовываться, пока список системных шрифтов по-прежнему показывает реальные шрифты хоста, и тогда две картины противоречат друг другу.
Третий подход представляет собой расширение, которое перехватывает связанные со шрифтами вызовы API и меняет сообщаемый список. Список можно отредактировать, а пиксели нельзя. Если список заявляет Microsoft YaHei, а текст на самом деле рисует шрифт FreeType хоста, измерение через Canvas покажет ширину, не принадлежащую Microsoft YaHei. Сообщаемое и наблюдаемое значения расходятся, и это расхождение измеримо.
У всех трёх подходов одна слабость. Они меняют один слой, будь то установка, оформление страницы или сообщаемый список, а остальные оставляют как есть. Согласованный CJK-результат требует, чтобы перечисление, поведение подстановки и отрисовка менялись вместе, потому что страница может сравнить любые два из них.
Выбор режима шрифтов для CJK-работы
BotBrowser описывает работу со шрифтами через --bot-fonts, у которого три режима. Профиль несёт набор шрифтов для своей целевой платформы, а режим определяет, как этот набор соотносится со шрифтами хоста. Документация BotBrowser по шрифтам описывает набор профиля как полный комплект стандартных шрифтов целевой платформы и указывает, что результаты перечисления соответствуют тому, что сообщила бы эта платформа.
--bot-fonts=profileиспользует набор шрифтов, встроенный в профиль, и является значением по умолчанию. Применяйте его, когда перечень шрифтов профиля и его поведение подстановки должны оставаться основными.--bot-fonts=expandиспользует шрифты профиля и позволяет сценарию подставлять шрифты хоста для символов, которые набор не покрывает. Применяйте его только тогда, когда сценарий сознательно допускает такую подстановку.--bot-fonts=realиспользует реальные шрифты хоста. Применяйте его для сравнения или тестов и ожидайте результата, зависящего от хоста, потому что набор профиля не используется.
Для большинства CJK-сценариев profile является правильной отправной точкой. Он удерживает доступность шрифтов и подстановку привязанными к платформе профиля, поэтому профиль Windows с китайской локалью сообщает Microsoft YaHei и SimSun, даже когда хостом служит сервер Linux без этих шрифтов. Это также избавляет от необходимости устанавливать CJK-шрифты на хост ради профиля.
Режим шрифтов лишь часть согласованной региональной настройки. Сочетайте CJK-профиль с локалью, списком языков и часовым поясом того же региона, как описано в материале о согласованности часового пояса, локали и языка. Параметры перечислены в справочнике по параметрам командной строки вместе с тарифным уровнем каждого. Ниже приведены три примера.
chrome --bot-profile="profiles/win11-zh-cn.enc" \
--bot-fonts=profile \
--bot-locale=zh-CN \
--bot-languages=zh-CN,zh,en \
--bot-timezone=Asia/Shanghai
chrome --bot-profile="profiles/win11-ja.enc" \
--bot-fonts=profile \
--bot-locale=ja-JP \
--bot-languages=ja,en \
--bot-timezone=Asia/Tokyo
chrome --bot-profile="profiles/win11-ko.enc" \
--bot-fonts=profile \
--bot-locale=ko-KR \
--bot-languages=ko,en \
--bot-timezone=Asia/Seoul
Режим expand требует взвешенного решения. Он полезен, когда на странице есть редкие иероглифы, символы или письменности, которые набор профиля не покрывает, потому что хост может предоставить глиф вместо пустого квадрата. Цена в том, что эти символы теперь берутся из шрифтов хоста, поэтому их вид зависит от машины. Выбирайте expand только тогда, когда полное покрытие важнее строгого соответствия платформе профиля, а profile оставляйте для сценариев, где цель состоит в согласованности.
Важен и сам профиль. Профиль, снятый с установки, которая уже использовала целевую локаль, содержит CJK-семейства, поставлявшиеся с этой конфигурацией, поэтому отдавайте предпочтение профилям, снятым с установки с подходящей локалью. Профиль, снятый с машины только на английском, не будет содержать полный китайский или японский набор, а никакой параметр не добавит набор, которого в профиле нет. Если сценарию нужны и японские, и китайские шрифты, используйте профиль, снятый с системы, где были оба языковых пакета. Об использовании одного профиля в разных операционных системах в целом читайте в материале о кроссплатформенных профилях браузера.
Проверка результата и границы возможностей
Простое сравнение ширины подтверждает базовую доступность шрифта. Измерьте строку, в которой смешаны латинские буквы и CJK-символы, в ожидаемом шрифте, а затем измерьте ту же строку в запасном шрифте, например monospace. Если две ширины различаются, указанное семейство найдено. Если они совпадают, браузер подставил другой шрифт. Используйте смешанную строку, потому что многие CJK-семейства дают каждому иероглифу одинаковое продвижение, и строка из одних иероглифов может показать равную ширину даже для разных шрифтов. Следующий фрагмент можно вставить в консоль разработчика тестовой страницы.
const ctx = document.createElement('canvas').getContext('2d');
const sample = 'Hello 你好 mmmlli';
ctx.font = '16px monospace';
const baseline = ctx.measureText(sample).width;
ctx.font = '16px "Microsoft YaHei", monospace';
const candidate = ctx.measureText(sample).width;
console.log({ baseline, candidate, found: candidate !== baseline });
Выполните ту же проверку для нескольких семейств, которые относятся к целевой платформе профиля, и для нескольких, которые к ней не относятся. Китайский профиль Windows должен находить Microsoft YaHei и SimSun и не должен находить PingFang SC. Японский профиль macOS должен находить Hiragino Sans и не должен находить Meiryo. Повторите проверку как минимум на двух хостовых операционных системах с тем же профилем. Если ответы меняются вместе с хостом, шрифты хоста просачиваются в результат, и первым делом нужно убедиться, что задан --bot-fonts=profile.
Соотносите смысл результата с его границами. Сравнение ширины показывает доступность. Оно не доказывает, что каждый глиф, каждая высота строки и каждая деталь растеризации совпадают с реальной машиной исходной платформы. Считайте его первой проверкой и дополните визуальным просмотром страницы с большим количеством CJK-текста на интересующем вас языке. Полезен небольшой порядок проверки.
- Убедитесь, что профиль снят с локалью и платформой, которые вы хотите представить.
- Убедитесь, что локаль, список языков и часовой пояс указывают на тот же регион, что и профиль.
- Выполните сравнение ширины для семейств, относящихся к целевой платформе, и для семейств, которые к ней не относятся.
- Откройте страницу с большим объёмом китайского, японского или корейского текста и поищите пропавшие глифы или пустые квадраты.
- Повторите на второй хостовой операционной системе с тем же профилем и сравните ответы.
У неожиданных результатов обычно немного причин. Символы, показанные как квадраты, говорят о том, что профиль не включает набор CJK-шрифтов для этого языка, поэтому выберите версию профиля, которая его включает. Различие ширины текста на двух хостах говорит о том, что отличаются версия BotBrowser или профиль, потому что обновления шрифтов между версиями могут менять метрики. Несогласованные интервалы в тексте с CJK и латиницей обычно указывают на различия подстановки, поэтому проверьте, что настройка шрифтов профиля покрывает обе письменности. Редкие символы, которые отображаются иначе, могут переходить на шрифты хоста. Вы можете сообщить о них, чтобы их добавили в будущие обновления набора шрифтов, или использовать expand, если сценарий сознательно допускает подстановку шрифтов хоста.
BotBrowser поддерживает --bot-fonts=profile, который использует набор шрифтов, встроенный в профиль, поэтому сообщаемые доступность, перечисление и подстановка CJK-шрифтов следуют целевой платформе профиля, а не шрифтам, установленным на хосте. Для CJK-сценария это позволяет проверить, что профиль с китайской, японской или корейской локалью остаётся согласованным при запуске на другой хостовой операционной системе. BotBrowser не может гарантировать, что собственные проверки сайта примут эту идентичность, не заменяет профиль, снятый с установки с подходящей локалью, и не контролирует шрифты самой страницы, её выбор подстановки в CSS и серверное поведение платформы.
Итог
Используйте --bot-fonts=profile с профилем, снятым для нужной CJK-локали, затем проверьте доступность шрифтов и ширину смешанного текста на нескольких хостах. Считайте результат подтверждением согласованности, а не доказательством совпадения каждого глифа или детали растеризации с физической машиной.
Открытые источники
- https://botbrowser.io/docs/fingerprint/font/ описывает режимы шрифтов, встроенные наборы шрифтов и кроссплатформенное поведение шрифтов.
- https://www.w3.org/TR/css-fonts-4/ является спецификацией CSS Fonts Module Level 4, которая охватывает подбор шрифтов и подстановку.
- https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/measureText описывает API измерения текста в Canvas, используемое для сравнения ширины.
Эта статья входит в руководство: Поверхности веб-платформы: карта проверки
Похожие статьи
Что такое отпечаток шрифтов? Согласованность текста между платформами
ОтпечаткиЗагрузка веб-шрифтов и стабильность макета без неожиданных сдвигов
ОтпечаткиFingerprinting измерения текста: субпиксельное отслеживание
ПлатформаКроссплатформенные профили: одна идентичность на каждом хосте
ПлатформаЗапуск профилей Windows-браузера на macOS и Linux
ОтпечаткиОтпечаток Canvas: как он работает и что помогает
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.