Подключение стилей

Leaflet опирается на набор CSS-правил, которые отвечают за корректное отображение карты, тайлов, контролов и стандартных элементов интерфейса. Без подключения стилей библиотека остаётся функционально рабочей, но визуально «разрушенной»: отсутствуют размеры контейнера карты, не отображаются элементы управления масштабом, маркеры теряют оформление, а всплывающие окна не имеют базовой структуры.

Базовая роль CSS в архитектуре Leaflet

Стили Leaflet выполняют несколько ключевых задач:

  • формируют геометрию карты (размеры контейнера, слои тайлов);
  • задают поведение элементов управления (zoom, attribution, layers);
  • обеспечивают позиционирование всплывающих окон и tooltip’ов;
  • определяют внешний вид маркеров и их иконок;
  • реализуют адаптацию под retina-дисплеи;
  • управляют слоями через z-index-иерархию.

CSS в Leaflet не является декоративным дополнением — это часть базовой отрисовки, без которой карта теряет структурную целостность.


Подключение через CDN

Наиболее простой способ подключения стилей — использование CDN-версии:

<link
  rel="stylesheet"
  href="https://unpkg.com/leaflet/dist/leaflet.css"
/>

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

Одновременно с CSS обычно подключается Jav * aScript:

<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>

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


Подключение через npm и сборщики

При использовании современных сборщиков (Vite, Webpack, Rollup) стили подключаются через импорт:

import "leaflet/dist/leaflet.css";

Такой подход обеспечивает:

  • включение CSS в итоговый бандл;
  • корректную работу tree-shaking (для JS-части);
  • контроль версий через package.json;
  • отсутствие внешних зависимостей во время выполнения.

При этом важно учитывать, что CSS Leaflet содержит ссылки на изображения (иконки маркеров), которые должны корректно резолвиться сборщиком.


Структура CSS Leaflet

Внутри leaflet.css можно выделить несколько логических блоков.

1. Контейнер карты

Ключевой элемент:

.leaflet-container {
    height: 100%;
    width: 100%;
}

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


2. Слои карты

Leaflet использует слоистую модель:

  • tilePane — тайлы
  • overlayPane — векторные слои
  • shadowPane — тени маркеров
  • markerPane — маркеры
  • tooltipPane — всплывающие подсказки
  • popupPane — всплывающие окна

Каждому слою соответствует свой z-index, определённый в CSS:

.leaflet-pane {
    position: absolute;
    top: 0;
    left: 0;
}

Иерархия слоёв обеспечивает предсказуемое перекрытие объектов.


3. Контролы интерфейса

Элементы управления масштабом и слоями оформляются через классы:

  • .leaflet-control
  • .leaflet-bar
  • .leaflet-control-zoom

Пример базовой стилизации:

.leaflet-bar a {
    background-color: #fff;
    border-bottom: 1px solid #ccc;
}

Эти стили задают визуальную консистентность кнопок и их hover-состояний.


4. Popups и tooltips

Всплывающие окна реализуются через:

  • .leaflet-popup
  • .leaflet-popup-content
  • .leaflet-tooltip

CSS управляет:

  • анимацией появления;
  • позиционированием «хвостика»;
  • ограничением ширины;
  • отступами и тенями.

Проблема размеров контейнера

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

Leaflet не задаёт фиксированную высоту карте автоматически. Поэтому:

#map {
    height: 400px;
}

или:

html, body, #map {
    height: 100%;
}

Без этого правило .leaflet-container { height: 100%; } не имеет эффекта, так как процентная высота зависит от родителя.


Подключение иконок маркеров

CSS Leaflet содержит ссылки на изображения:

  • marker-icon.png
  • marker-icon-2x.png
  • marker-shadow.png

Они используются через стандартные пути, например:

background-image: url(images/marker-icon.png);

Проблема сборщиков

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


Решение проблем с иконками

В стандартной конфигурации Leaflet использует:

import L from "leaflet";
import "leaflet/dist/leaflet.css";

Однако пути к изображениям могут быть некорректны. Для исправления применяется переопределение:

import iconUrl from "leaflet/dist/images/marker-icon.png";
import iconShadow from "leaflet/dist/images/marker-shadow.png";

L.Icon.Default.mergeOptions({
    iconUrl,
    shadowUrl: iconShadow
});

Это обеспечивает явное указание ресурсов, независимо от сборщика.


Retina-экраны и адаптивность

Leaflet поддерживает высокоплотные дисплеи через @2x изображения.

CSS автоматически выбирает:

  • обычные иконки для стандартных экранов;
  • marker-icon-2x.png для retina.

Логика выбора основана на media queries:

@media
(-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {
    .leaflet-tile {
        /* использование high-res тайлов */
    }
}

Переопределение стандартных стилей

Leaflet допускает полную кастомизацию через переопределение классов.

Изменение внешнего вида карты

.leaflet-container {
    background: #1e1e1e;
}

Кастомизация контролов

.leaflet-control-zoom a {
    background-color: #222;
    color: #fff;
}

Изменение popups

.leaflet-popup-content-wrapper {
    border-radius: 0;
    background: #111;
    color: #fff;
}

Приоритеты CSS и конфликт стилей

Leaflet использует классы с высокой специфичностью, но не применяет !important повсеместно. Это означает:

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

Особенно часто конфликт возникает с:

  • box-sizing;
  • img { max-width: 100%; };
  • глобальными overflow: hidden.

Работа с CSS в SPA-приложениях

В SPA (React, Vue, Angular) подключение Leaflet CSS имеет особенности.

React / Vite

import "leaflet/dist/leaflet.css";

Подключение в entry-файле гарантирует, что стили попадут в бандл до рендера компонентов карты.

Code splitting

При ленивой загрузке карты возможна ситуация, когда CSS ещё не загружен. Это приводит к «миганию» неоформленного интерфейса.


Порядок загрузки и рендеринга

Правильная последовательность:

  1. загрузка leaflet.css;
  2. создание DOM контейнера;
  3. инициализация карты через L.map();
  4. добавление тайлов и слоёв.

Нарушение порядка приводит к:

  • неправильной высоте контейнера;
  • смещённым контролам;
  • отсутствию корректных размеров тайлов при первом render cycle.

Изоляция стилей в сложных проектах

В крупных приложениях Leaflet CSS часто конфликтует с:

  • CSS Modules;
  • Tailwind preflight;
  • styled-components глобальными reset-ами.

Решения:

  • локальная обёртка контейнера карты;
  • отключение глобальных reset-стилей для .leaflet-*;
  • изоляция через shadow DOM (редко, но возможно).

Пример:

.map-wrapper .leaflet-container {
    font-family: Arial, sans-serif;
}

Кастомизация через переменные и постобработку

Хотя Leaflet не использует CSS variables по умолчанию, стили можно адаптировать через препроцессоры:

$popup-bg: #2b2b2b;

.leaflet-popup-content-wrapper {
    background: $popup-bg;
}

Это упрощает поддержку темной темы и динамических интерфейсов.


Итоговая структура подключения

Типовой минимальный набор:

<link rel="stylesheet" href="leaflet.css">
<script src="leaflet.js"></script>

или через модульную систему:

import "leaflet/dist/leaflet.css";
import L from "leaflet";

Корректное подключение стилей является обязательным условием работоспособности визуальной части карты, включая слои, контролы, маркеры и всплывающие элементы.