Контролы в Leaflet размещаются поверх карты в фиксированных областях
интерфейса и привязываются не к географическим координатам, а к экранным
углам контейнера карты. Основной механизм позиционирования основан на
предопределённых зонах: topleft, topright,
bottomleft, bottomright, которые определяют, в
какой части DOM-контейнера будет находиться элемент управления.
Каждый контрол в Leaflet реализуется через систему
L.Control и при добавлении на карту получает контейнер
DOM-элемент, который помещается в один из четырёх слоёв:
Эти зоны соответствуют CSS-контейнерам внутри карты:
.leaflet-top.leaflet-bottom.leaflet-left.leaflet-rightКомбинация этих классов формирует итоговую позицию, например:
.leaflet-top .leaflet-left → topleft.leaflet-top .leaflet-right →
toprightКаждый контрол автоматически инжектируется в соответствующий контейнер и получает вертикальное и горизонтальное выравнивание через CSS.
Позиция задаётся через опцию position в
конструкторе:
L.control({ position: 'topright' }).addTo(map);
Возможные значения строго ограничены четырьмя вариантами:
toplefttoprightbottomleftbottomrightЛюбое другое значение игнорируется и приводит к использованию
значения по умолчанию (topright для большинства встроенных
контролов).
При создании стандартных контролов поведение аналогично:
L.control.zoom({ position: 'bottomright' }).addTo(map);
L.control.scale({ position: 'bottomleft' }).addTo(map);
Контейнер карты формируется как набор вложенных DOM-слоёв:
.leaflet-map-pane
├── .leaflet-tile-pane
├── .leaflet-shadow-pane
├── .leaflet-overlay-pane
├── .leaflet-marker-pane
├── .leaflet-tooltip-pane
└── .leaflet-control-container
├── .leaflet-top
│ ├── .leaflet-left
│ └── .leaflet-right
└── .leaflet-bottom
├── .leaflet-left
└── .leaflet-right
Все контролы добавляются именно в
.leaflet-control-container, а затем распределяются по
соответствующим зонам.
Если несколько контролов размещены в одной зоне, их порядок зависит от порядка добавления на карту:
L.control.zoom({ position: 'topright' }).addTo(map);
L.control.layers(null, null, { position: 'topright' }).addTo(map);
Контрол, добавленный позже, визуально окажется ниже в вертикальном стеке (или правее/левее в зависимости от CSS-направления).
Для управления порядком используется принцип:
CSS использует flex или block потоковое
расположение внутри контейнеров.
Каждый контрол обёрнут в элемент с классом
leaflet-control, который имеет базовые стили:
marginbox-shadowborder-radiuspointer-events: autoГруппы контролов внутри угла получают дополнительные контейнеры:
.leaflet-bar — для кнопочных контролов (zoom).leaflet-control-layers — для слоёвОтступ между контролами задаётся через CSS:
.leaflet-top .leaflet-left .leaflet-control {
margin-top: 10px;
margin-left: 10px;
}
Изменение этих значений позволяет управлять плотностью интерфейса.
Встроенные контролы можно переопределять через опции карты:
const map = L.map('map', {
zoomControl: false,
attributionControl: false
});
После отключения их можно создать заново с нужной позицией:
L.control.zoom({ position: 'bottomright' }).addTo(map);
Это позволяет полностью перестроить интерфейс управления.
Любой кастомный контрол наследуется от L.Control и
обязан реализовать метод onAdd:
const CustomControl = L.Control.extend({
onAdd: function(map) {
const div = L.DomUtil.create('div', 'custom-control');
div.innerHTML = 'Кнопка';
return div;
}
});
Добавление с позиционированием:
L.control.customControl = function(opts) {
return new CustomControl(opts);
};
L.control.customControl({ position: 'topright' }).addTo(map);
Позиционирование работает автоматически через механизм базового класса.
При ресайзе контейнера карты:
.leaflet-control-container пересчитывает размерыCSS обеспечивает адаптацию без участия JavaScript.
Контейнеры контролов доступны через API карты:
map.getContainer().querySelector('.leaflet-control-container');
Каждый контрол имеет ссылку на DOM-элемент:
control.getContainer();
Это позволяет динамически изменять стили:
control.getContainer().style.marginTop = '20px';
Контролы располагаются поверх всех слоёв карты благодаря
z-index:
.leaflet-pane — слои карты.leaflet-control-container — UI поверх картыКонтейнер контролов всегда имеет больший приоритет, чем тайлы и маркеры, что обеспечивает стабильную видимость интерфейса.
При добавлении большого числа контролов в одну зону возможны ситуации перекрытия. Поведение определяется CSS-потоком:
Для предотвращения наложений применяется:
marginХотя Leaflet ограничивает API четырьмя позициями, визуально можно создавать дополнительные зоны через CSS-переопределения:
.leaflet-custom-top-center {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
}
И подключение контролов вне стандартной системы:
const div = L.DomUtil.create('div', 'leaflet-control leaflet-custom-top-center');
map.getContainer().appendChild(div);
Такой подход полностью обходится без встроенного механизма
L.Control.
Контролы делятся на логические группы:
Каждый тип может занимать отдельную зону для снижения визуальной нагрузки интерфейса.
На мобильных экранах контейнеры автоматически сжимаются:
CSS медиазапросы Leaflet обеспечивают адаптивность без дополнительного кода.
Позиция контролов может быть изменена после добавления:
control.setPosition('bottomleft');
При этом:
Это позволяет перестраивать интерфейс без пересоздания контролов.