Fallback шрифты

В MapLibre GL JS текст на карте не использует системные шрифты браузера напрямую: вся типографика рендерится через заранее подготовленные векторные глифы, которые загружаются с сервера и компилируются в SDF-изображения для WebGL. Именно поэтому механизм резервных (fallback) шрифтов здесь отличается от привычного CSS font-family.

В основе работы лежит концепция fontstack — упорядоченного списка шрифтов, которые последовательно проверяются при отсутствии нужных символов в первом варианте.

В слоях символов (symbol layer) параметр layout.text-font задаёт массив шрифтов:

"text-font": ["Noto Sans Regular", "Arial Unicode MS Regular"]

Каждый элемент — это не локальный системный шрифт, а имя набора глифов, доступного на сервере glyphs. При рендеринге MapLibre GL JS запрашивает глифы именно по этому имени.

Порядок имеет критическое значение: первый доступный fontstack используется для каждого конкретного символа, если он содержит нужный Unicode-глиф.

Если символ отсутствует в первом шрифте, движок автоматически переходит к следующему элементу массива.

Глифы как основа fallback-механизма

MapLibre GL JS не оперирует TTF/OTF файлами в рантайме. Вместо этого используется сервер глифов, который возвращает PBF-контейнеры с растеризованными символами.

Типичный запрос выглядит так:

/fonts/{fontstack}/{range}.pbf

где:

  • fontstack — имя набора шрифтов (например, Noto Sans Regular)
  • range — диапазон Unicode-символов (например, 0-255)

Ключевой момент: fallback реализуется не на уровне браузера, а на уровне выбора glyph range и fontstack.

Поведение fallback при отсутствии символов

Если символ отсутствует во всех указанных fontstack:

  • символ не рендерится
  • отображается пустое место или “tofu” (□)
  • либо используется запасной глобальный fontstack, если он предусмотрен стилем

MapLibre не пытается «склеить» текст из локальных шрифтов устройства — всё зависит от доступности глифов на сервере.

Правильное построение цепочки резервных шрифтов

Типичная стратегия включает несколько уровней:

"text-font": [
  "Inter Regular",
  "Noto Sans Regular",
  "Arial Unicode MS Regular"
]

Логика порядка

  • Первый шрифт — основной (оптимизированный под бренд или дизайн)
  • Второй — универсальный Unicode fallback
  • Третий — максимально широкий coverage (часто CJK/legacy)

Такой порядок позволяет контролировать внешний вид, сохраняя поддержку максимального количества символов.

Кириллица, латиница и расширенные наборы

Кириллица часто становится источником проблем, если используется узкий латинский fontstack.

Например:

"text-font": ["Roboto Regular", "Open Sans Regular"]

Оба шрифта могут не содержать полного набора кириллических символов, если сервер glyphs был собран без поддержки расширенных диапазонов.

Решение — использование шрифтов с Unicode coverage:

  • Noto Sans (Google)
  • DejaVu Sans
  • Source Sans Pro (с расширенными сборками)

CJK и иероглифические системы письма

Для китайского, японского и корейского текста fallback становится критически важным из-за огромного количества глифов.

Обычно применяется стратегия разделения:

"text-font": [
  "Noto Sans SC Regular",
  "Noto Sans JP Regular",
  "Noto Sans KR Regular",
  "Noto Sans Regular"
]

Каждый fontstack содержит специализированный набор глифов, и MapLibre выбирает первый подходящий.

Особенность CJK в том, что один символ может отсутствовать даже в «универсальном» шрифте, поэтому fallback цепочка должна быть длиннее и более специализированной.

Латинские расширения и диакритика

Символы вроде:

  • š, ž, ł, ğ, ñ
  • математические и типографские знаки

часто отсутствуют в базовых шрифтах. Если fontstack не покрывает Latin Extended диапазоны, MapLibre будет последовательно переходить к следующему набору.

Это особенно заметно в смешанных слоях, где названия городов содержат разные языковые системы.

Влияние glyphs endpoint на fallback

Fallback зависит не только от text-font, но и от того, как сервер генерирует glyph PBF.

Если сервер содержит только:

  • ASCII диапазон
  • частичный Latin-1

то даже корректный fontstack не поможет.

Типичный production endpoint должен включать:

/fonts/Noto Sans Regular/{0-255}.pbf
/fonts/Noto Sans Regular/{256-511}.pbf
/fonts/Noto Sans Regular/{CJK ranges}.pbf

Отсутствие диапазонов ломает fallback на уровне данных, а не логики клиента.

SDF-глифы и визуальная консистентность

MapLibre использует Signed Distance Field (SDF) для текста. Это означает:

  • текст масштабируется без потери качества
  • один и тот же glyph может использоваться в разных размерах
  • цвет и обводка применяются шейдерами

Fallback-шрифты должны быть согласованы по метрикам:

  • baseline
  • x-height
  • advance width

Иначе текст «прыгает» при переходе между fontstack.

Частые ошибки при настройке fallback

1. Использование системных шрифтов

"text-font": ["Arial", "Helvetica"]

Ошибка: MapLibre не использует локальные системные шрифты.

2. Несовпадение имён fontstack и сервера glyphs

"text-font": ["NotoSans"]

Но сервер ожидает:

"Noto Sans Regular"

Результат — отсутствие текста.

3. Отсутствие Unicode fallback

Если указан только один шрифт, любые отсутствующие символы превращаются в пустые квадраты.

4. Перегруженные цепочки

Слишком длинный список:

"text-font": ["A", "B", "C", "D", "E", "F"]

увеличивает стоимость поиска glyph range.

Производительность fallback-цепочек

Каждый fontstack увеличивает вероятность дополнительных запросов:

  • MapLibre запрашивает range для каждого fontstack
  • при отсутствии glyph происходит переход к следующему
  • увеличивается latency при первом рендере текста

Оптимальная стратегия:

  • 2–3 fontstack максимум
  • приоритет универсальных шрифтов с широким coverage
  • предварительно собранные glyph atlases

Интернационализация и универсальные наборы

На практике наиболее устойчивый подход — использование семейства Noto:

  • Noto Sans
  • Noto Serif
  • Noto Sans CJK

Они покрывают большинство Unicode-блоков и минимизируют необходимость сложных fallback-цепочек.

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

Поведение при смешанных языках в одном тексте

Если строка содержит:

"Москва Tokyo 北京"

MapLibre разбивает текст на glyph runs:

  • латиница/кириллица → один fontstack
  • CJK → другой fontstack

Fallback применяется не к строке целиком, а к отдельным сегментам, что позволяет корректно комбинировать разные системы письма в одном label.

Связь с стилями MapLibre Style Spec

Fallback определяется исключительно в:

layout: {
  "text-font": [...]
}

CSS-правила не влияют на выбор шрифтов. Любые font-family из DOM игнорируются, поскольку WebGL-canvas изолирован от браузерного текстового рендеринга.

Это фундаментальное отличие от HTML-типографики, где fallback управляется CSS каскадом.

Практическая модель устойчивого fallback

Надёжная конфигурация обычно строится по принципу:

  1. брендовый шрифт (узкий, эстетический)
  2. универсальный sans-serif с большим Unicode coverage
  3. глобальный fallback (Noto или аналог)

Такой подход снижает вероятность «провалов» текста и обеспечивает стабильный визуальный результат при любых данных слоя.