经纬志
首页 / 实战手册 / 瓦片

瓦片之间出现 1 像素白线,缩放后像蛛网

先看结论

每张瓦片都完整加载了,但拼起来满屏细白线,缩放级别越小越明显。

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

现象

在 2560×1440 的屏幕上,瓦片拼接处可见 1 像素宽的浅白色缝隙, 采用深色影像底图时尤其明显。放大到 18 级缝隙变少,缩到 10 级几乎成网状。

截图放大后可以确认缝隙宽度正好 1 个 CSS 像素, 且缝隙位置随地图平移而移动。

原因

三个因素叠加会导致亚像素缝隙:

  • 地图容器的宽高不是瓦片尺寸的整数倍,瓦片定位出现小数像素。
  • 浏览器对 transform: translate3d(x, y, 0) 做抗锯齿,边缘被半透明化。
  • 页面设置了 transform: scale() 或浏览器缩放(110%、125%), 导致实际设备像素比与 tileSize 不匹配。

Leaflet 默认的瓦片定位带小数,配合硬件加速就会出现这条缝。

排查过程

  1. 把浏览器缩放到 100%,看缝隙是否消失。消失则为缩放导致。
  2. 在控制台读 layer.getContainer().style.transform,看是否有小数。
  3. 检查地图容器宽高:宽 1024、高 768 是整数倍关系,宽 1023 就会出现半像素。
  4. 检查页面是否对地图外层元素做了 scale 或 zoom。
console.log(layer.getContainer().style.transform);
// translate3d(1023.5px, 767.5px, 0px)   <- 半像素,必出缝

console.log(map.getSize());   // Point(1023, 767) 不是 256 的整数倍

解决方案

三种手段按副作用从小到大:先给瓦片容器加 1 像素外扩, 再对齐容器尺寸,最后调整渲染参数。

/* 1. 让瓦片比格子大 1 像素,缝隙被覆盖 */
.leaflet-tile {
  width: 257px !important;
  height: 257px !important;
}

/* 2. 关闭瓦片层的硬件加速,避免小数像素抗锯齿 */
.leaflet-tile-container {
  will-change: auto;
  transform-style: flat;
}
// 3. 让容器尺寸为 256 的整数倍
const el = document.getElementById('map');
const w = Math.floor(el.clientWidth / 256) * 256;
el.style.width = w + 'px';

// 4. OpenLayers:给瓦片像素比留余量
new TileLayer({
  source: new XYZ({ url: '...', tilePixelRatio: 1 }),
  preload: 2
});

高分屏要区分 tileSize 与 detectRetina。 使用 512 像素瓦片时把 tileSize 设为 512, 并关闭 detectRetina,否则 Leaflet 会按 256 布局,缝隙翻倍。

验证

在深浅两种底图上各平移 10 秒,截图像素级检查,拼接处不再有连续白线; 切换浏览器缩放 100%、110%、125% 均正常。

console.assert(!/\.\d/.test(layer.getContainer().style.transform), '仍存在小数像素定位');
// 容器尺寸校验
console.assert(map.getSize().x % 256 === 0 || map.getSize().x % 512 === 0, '容器宽非瓦片整数倍');

适用版本

库版本说明
Leaflet1.7 ~ 1.9默认小数定位,需 CSS 或尺寸对齐
OpenLayers6.x ~ 9.xpreload 与 tilePixelRatio 影响缝隙
Chrome / Edge90 及以上硬件加速下抗锯齿更明显
引用本文

经纬志(2026)。《瓦片之间出现 1 像素白线,缩放后像蛛网》。https://www.jingweizhi.com/cookbook/tile-seam-gap.html(访问日期 2026-11-03)。