经纬志
首页 / Leaflet / 教程

移动端适配

先看结论

Leaflet 自带触摸支持,双击缩放、双指缩放、拖动惯性都不需要额外配置。 手机上真正要处理的是三件事:容器高度、手指的点击精度、以及页面滚动与地图拖动的争抢。

最后验证 2026-11-03 · Leaflet 1.9.4 · 更新 2026-10-29 · 引用本文

容器高度:不要用 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。

手势与触摸选项

选项默认移动端建议
doubleClickZoomtrue双击放大;与页面双击缩放冲突时可关闭
inertiatrue松手后的惯性滑动,低端设备可关闭
touchZoomtrue双指缩放,关闭会让用户无法放大
draggingtrue保持开启;页面内嵌小地图可考虑关闭
bounceAtZoomLimitstrue到最大级别时回弹,可按需关闭
zoomControltrue按钮小且挡视野,常关掉改用双指
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)。