移动端适配
Leaflet 自带触摸支持,双击缩放、双指缩放、拖动惯性都不需要额外配置。 手机上真正要处理的是三件事:容器高度、手指的点击精度、以及页面滚动与地图拖动的争抢。
容器高度:不要用 100vh
移动浏览器的地址栏会隐藏与显示,100vh 取的是「地址栏隐藏时」的高度,
于是页面底部被裁掉一截,地图下边缘的控件永远点不到。
100dvh(动态视口高度)随地址栏变化实时调整,是现在的标准解法。
html, body {
height: 100%;
margin: 0;
overscroll-behavior: none; /* 阻止下拉刷新与橡皮筋效果 */
}
#map {
height: 100vh; /* 老浏览器回退 */
height: 100dvh; /* 随地址栏变化 */
padding-bottom: env(safe-area-inset-bottom);
}
还需要在 head 里保留 viewport 声明。
漏写时移动端按 980 像素宽的虚拟视口渲染,地图会被整体缩小,字小到看不清。
<meta name="viewport"
content="width=device-width, initial-scale=1, viewport-fit=cover">
viewport-fit=cover 才会让 env(safe-area-inset-*)
返回刘海屏的真实数值;不加时该变量恒为 0。
手势与触摸选项
| 选项 | 默认 | 移动端建议 |
|---|---|---|
doubleClickZoom | true | 双击放大;与页面双击缩放冲突时可关闭 |
inertia | true | 松手后的惯性滑动,低端设备可关闭 |
touchZoom | true | 双指缩放,关闭会让用户无法放大 |
dragging | true | 保持开启;页面内嵌小地图可考虑关闭 |
bounceAtZoomLimits | true | 到最大级别时回弹,可按需关闭 |
zoomControl | true | 按钮小且挡视野,常关掉改用双指 |
var isTouch = window.matchMedia('(pointer: coarse)').matches;
var map = L.map('map', {
center: [39.907359, 116.391263],
zoom: isTouch ? 12 : 11,
zoomControl: !isTouch,
touchZoom: true,
inertia: !isTouch,
attributionControl: true
});
if (isTouch) {
// 控件移到右上,避开底部手势条与手指遮挡
L.control.scale({ position: 'topright' }).addTo(map);
}
点击区域与控件尺寸
桌面端的 12 像素圆点在手指下只有约 4 毫米,基本点不中。
移动端的可点对象建议不小于 44×44 逻辑像素:
把小圆点换成 L.marker 的大图标,或者给圆点设一个透明的大命中区。
// 视觉半径 6,实际命中区 22:用两条叠加的圆实现
var hit = L.circleMarker(latlng, {
radius: 22, stroke: false, fillOpacity: 0
}).addTo(map);
L.circleMarker(latlng, {
radius: 6, color: '#17694a', fillOpacity: 0.9
}).addTo(map);
hit.on('click', function () {
L.popup().setLatLng(latlng).setContent('监测点 A').openOn(map);
});
反过来用 L.marker 时,图标 44 像素、iconAnchor 取中心,
再加 keyboard: true,触屏与键盘都能操作。
页面滚动与地图拖动争抢
地图嵌在长页面中间时,手指在地图上滑动,浏览器不知道是要滚页面还是拖地图,
结果是页面跟着滚,地图纹丝不动。CSS 里给容器加 touch-action: none
可以把这块区域的手势全部交给 Leaflet。
#map {
touch-action: none;
}
/* 需要保留页面滚动的场景:只在小地图上禁用 */
.map-mini {
touch-action: pan-y;
}
拖动手感来自惯性。Leaflet 的 inertia 默认开启,
松手后地图继续滑一段再停。低性能设备上可以把 inertiaDeceleration
调大,让滑动更快停下,减少重绘压力。
注意事项
iOS 上双击会放大整个页面
双击缩放地图时,Safari 可能同时把页面放大。在容器上设
touch-action: manipulation 或用
map.doubleClickZoom.disable() 并改用双指缩放,都能规避。
旋转屏幕后地图错位
横竖屏切换改变容器尺寸,Leaflet 不会自动感知。
监听 orientationchange 或 resize,延迟一帧后调用
map.invalidateSize()。
底部被系统手势条覆盖
全屏地图的底部控件会落在 iOS 的 Home 指示条区域。
给控件容器加上 padding-bottom: env(safe-area-inset-bottom),
或者把控件统一放到右上角。
经纬志(2026)。《移动端适配》。https://www.jingweizhi.com/leaflet/tutorial/mobile.html(访问日期 2026-11-03)。