Альтернативный текст

Альтернативный текст и доступность в Mapbox GL JS

В веб-картографии на основе Mapbox GL JS вопрос доступности выходит за пределы визуального отображения данных. Альтернативный текст используется не только как замена изображения, но как способ передачи смысловой информации пользователям вспомогательных технологий, а также как дополнительный слой семантики для элементов интерфейса карты.

В контексте Mapbox GL JS отсутствует единый универсальный механизм «alt» для всей карты, поскольку карта формируется из множества слоёв, тайлов, векторных данных и DOM-элементов. Поэтому альтернативное описание реализуется на разных уровнях: через HTML-разметку, свойства слоёв, подписи символов и программную генерацию доступных атрибутов.


Альтернативный текст в веб-картах выполняет несколько функций:

  • описание географических объектов;
  • передача смысла визуальных символов;
  • поддержка экранных читалок;
  • замена визуальных маркеров при невозможности их восприятия;
  • уточнение интерактивных элементов.

В Mapbox GL JS основная сложность заключается в том, что визуальный слой не является DOM-структурой по умолчанию. Отрисовка выполняется через WebGL, поэтому стандартные атрибуты HTML (alt, title) применимы только к отдельным компонентам, создаваемым поверх карты.


HTML-маркеры и атрибут aria-label

Наиболее прямой способ задания альтернативного текста реализуется через HTML-маркеры. Такие маркеры представляют собой DOM-элементы, размещённые поверх карты.

const markerElement = document.createElement('div');
markerElement.className = 'custom-marker';

markerElement.setAttribute('role', 'img');
markerElement.setAttribute('aria-label', 'Маркер: центр города и административное здание');

new mapboxgl.Marker(markerElement)
  .setLngLat([69.2401, 53.2145])
  .addTo(map);

В данном случае aria-label заменяет визуальную информацию, встроенную в иконку маркера. Атрибут role="img" задаёт семантику изображения для вспомогательных технологий.

При использовании текстовых HTML-элементов внутри маркеров альтернативный текст часто дублирует содержимое:

const el = document.createElement('div');
el.innerText = 'A';
el.setAttribute('aria-label', 'Маркер A: точка интереса');

new mapboxgl.Marker(el)
  .setLngLat([69.1, 53.2])
  .addTo(map);

Символьные слои и текстовые подписи

Векторные слои Mapbox GL JS используют декларативную модель. Для символов (symbol layer) альтернативный текст частично реализуется через текстовые поля (text-field), которые фактически становятся визуальной подписью.

map.addLayer({
  id: 'cities',
  type: 'symbol',
  source: 'cities-data',
  layout: {
    'text-field': ['get', 'name'],
    'text-size': 12
  }
});

Хотя text-field не является альтернативным текстом в классическом HTML-смысле, он выполняет ту же функцию — передаёт смысл объекта через текстовое представление.

Для повышения доступности используется дублирование данных в свойствах объектов:

map.addLayer({
  id: 'pois',
  type: 'symbol',
  source: 'pois',
  layout: {
    'text-field': ['get', 'label']
  }
});

Если данные содержат сложные визуальные иконки (icon-image), рекомендуется обеспечивать текстовую альтернативу через свойства источника.


Слой иконок и проблема отсутствия alt в WebGL

Иконки в Mapbox GL JS задаются через sprite и свойство icon-image. Эти изображения не имеют прямого HTML-эквивалента, поэтому альтернативный текст не существует на уровне WebGL.

map.addLayer({
  id: 'restaurants',
  type: 'symbol',
  source: 'places',
  layout: {
    'icon-image': 'restaurant-15',
    'icon-size': 1
  }
});

Для компенсации отсутствия текстовой семантики используется:

  • text-field рядом с иконкой;
  • title через интерактивные popups;
  • aria-label на контейнере карты;
  • скрытые DOM-элементы для экранных читалок.

Popups как источник альтернативного описания

Всплывающие окна часто становятся основным носителем расширенного описания объекта. Их содержимое может рассматриваться как расширенный альтернативный текст.

new mapboxgl.Popup()
  .setLngLat([69.2401, 53.2145])
  .setHTML(`
    <div role="dialog" aria-label="Информация об объекте">
      <h3>Административное здание</h3>
      <p>Основной городской центр управления</p>
    </div>
  `)
  .addTo(map);

Использование role="dialog" и aria-label позволяет связать визуальное окно с семантическим описанием.


Доступность контейнера карты

Сам контейнер Mapbox GL JS требует явного задания роли и описания, поскольку canvas-элемент не содержит семантики.

map.getCanvas().setAttribute('role', 'application');
map.getCanvas().setAttribute(
  'aria-label',
  'Интерактивная карта с объектами инфраструктуры и географическими данными'
);

При необходимости более детального описания применяется связанный текстовый блок:

<div id="map-description" hidden>
  Карта отображает города, дороги и точки интереса региона.
</div>
map.getCanvas().setAttribute('aria-describedby', 'map-description');

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

При работе с GeoJSON альтернативные описания часто формируются из свойств объекта.

map.addSource('locations', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: [
      {
        type: 'Feature',
        properties: {
          name: 'Парк культуры',
          description: 'Городской парк с зелёной зоной и аллеями'
        },
        geometry: {
          type: 'Point',
          coordinates: [69.3, 53.2]
        }
      }
    ]
  }
});

На основе этих данных формируется доступный текст:

const feature = features[0];
const altText = `${feature.properties.name}. ${feature.properties.description}`;

Такой подход позволяет синхронизировать визуальное представление и смысловую нагрузку.


Обработка событий и доступность интерактивных объектов

При взаимодействии с объектами карты важно формировать текстовое описание через события click или mouseenter.

map.on('click', 'pois', (e) => {
  const feature = e.features[0];
  const description = feature.properties.description;

  const announcement = document.getElementById('screen-reader-output');
  announcement.textContent = description;
});
<div id="screen-reader-output" aria-live="polite"></div>

aria-live="polite" обеспечивает озвучивание изменений без прерывания текущего фокуса.


Скрытые текстовые слои как замена визуального контента

В случаях сложных визуализаций используется параллельный скрытый слой DOM, содержащий структурированное описание карты.

<ul id="map-accessibility-layer" hidden>
  <li>Объект: мост через реку</li>
  <li>Объект: железнодорожная станция</li>
  <li>Объект: жилой район</li>
</ul>

Такой слой может синхронизироваться с данными карты и обновляться при изменении viewport.


Ограничения альтернативного текста в Mapbox GL JS

Архитектура WebGL накладывает ряд ограничений:

  • отсутствие нативного alt для canvas;
  • невозможность привязки ARIA к отдельным пикселям;
  • зависимость доступности от внешнего DOM-слоя;
  • необходимость дублирования данных в нескольких представлениях.

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


Структурирование текстовой эквивалентности геоданных

Для сложных картографических систем применяется подход разделения данных и представления:

  • геометрия описывает положение;
  • свойства содержат семантику;
  • DOM-слой обеспечивает доступность;
  • события связывают визуальное и текстовое представление.

Такое разделение позволяет формировать полную текстовую эквивалентность визуальной карты без потери структуры данных.