经纬志
首页 / 实战手册 / 样式与渲染

面图层盖住了线图层,调 zIndex 反而更糟

先看结论

道路线被行政区面压在下面,设了 zIndex: 999 依旧没变,甚至整条线消失了。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

图层加入顺序是:面(行政区)→ 线(道路)→ 点(POI)。 实际渲染却是面压住了线,点又压在面上面。 给线图层加 { zIndex: 999 } 后,线彻底不见, 拖动地图时才偶尔闪一下。

原因

Leaflet 的 zIndex 不是图层之间的排序,而是同一个渲染器内部 的容器层级。默认情况下所有矢量图层共用同一个 SVG 渲染器, zIndex 被渲染器忽略,真正决定顺序的是 addLayer 的先后。

设了 999 后,Leaflet 会给该图层单独创建一个渲染器(因为 pane 或 renderer 变化),新渲染器的 pane 默认 z-index 是 400, 反而落到了面图层下面。

OpenLayers 不同:图层顺序由 layer.getZIndex() 或加入 collection 的次序决定, 给 zIndex 赋值确实生效,但数字越大越靠上。

库控制层级的方式zIndex 是否有效
Leafletpane 或 bringToFront()跨 pane 有效,同 pane 内无效
OpenLayerslayer.setZIndex(n)有效
Mapbox GL样式里 layers 数组顺序无 zIndex 概念

排查过程

  1. 在 Elements 面板看各图层的 .leaflet-pane 与 z-index。
  2. 检查代码里是否给多个图层设了不同 renderer 或 pane。
  3. 看加入顺序,Leaflet 同 pane 内后加的在上面。
  4. 给面图层设置 interactive: false 后测试,排除点击事件干扰。
console.log(map.getPane('overlayPane').style.zIndex);   // 400
// 自定义 pane 若没设 z-index,会和默认 pane 抢层级
document.querySelectorAll('.leaflet-pane').forEach(p =>
  console.log(p.className, getComputedStyle(p).zIndex));

解决方案

用自定义 pane 明确分层,或直接调整加入顺序。 不要在同一 pane 内指望 zIndex 排序。

// 1. 建立三个专用 pane,层级写清楚
map.createPane('areas');
map.getPane('areas').style.zIndex = 410;

map.createPane('roads');
map.getPane('roads').style.zIndex = 420;

map.createPane('pois');
map.getPane('pois').style.zIndex = 430;

L.geoJSON(areaData, {
  pane: 'areas',
  style: { fillOpacity: 0.35, color: '#1a6fd4', weight: 1 }
}).addTo(map);

L.geoJSON(roadData, {
  pane: 'roads',
  style: { color: '#e8590c', weight: 3 }
}).addTo(map);

L.geoJSON(poiData, { pane: 'pois' }).addTo(map);
// OpenLayers:zIndex 直接生效
const roads = new VectorLayer({ source: roadSource, zIndex: 20 });
const areas = new VectorLayer({ source: areaSource, zIndex: 10 });
map.addLayer(areas);
map.addLayer(roads);

验证

道路线完整压在行政区面之上,点击道路能命中线图层; map.getPane('roads').style.zIndex > map.getPane('areas').style.zIndex。

const zi = n => Number(map.getPane(n).style.zIndex);
console.assert(zi('roads') > zi('areas'), '层级仍不对');
console.assert(zi('pois') > zi('roads'), '点被压住');

适用版本

库版本说明
Leaflet1.9.x默认 pane:tilePane 200、overlayPane 400、markerPane 600
OpenLayers6.x ~ 9.xsetZIndex 生效
Mapbox GL JS2.x / 3.x用 moveLayer(id, beforeId) 调整
引用本文

经纬志(2026)。《面图层盖住了线图层,调 zIndex 反而更糟》。https://www.jingweizhi.com/cookbook/layer-order-cover.html(访问日期 2026-11-03)。