首页 / 实战手册 / MapLibre 样式与图层
自定义图标全部 404,标记变成空白
先看结论
符号图层加好了,样式里也写了 icon-image,地图上却一个图标都没有,
网络面板里一片红色 404。
现象
控制台报图片加载失败,所有 icon-image 引用都失效:
Uncaught Error: Could not load image because of 404 Not Found.
at maplibre-gl.js:4211
GET /icons/pin.png 404 (Not Found)
GET /icons/pin@2x.png 404 (Not Found)
有时图片请求是 200,但地图上仍然没有图标,并且没有任何报错。
原因
两类问题混在一起:
- 路径问题。资源放在
/public/icons,打包后实际路径是/assets/icons,但代码里写的是相对路径./icons/pin.png,页面在子路由下就变成 404。 - 时机问题。用
img.onload之外的方式调用addImage,图片还没解码完就注册,注册失败或注册成空图。 - 高清屏问题。只提供了 1 倍图,MapLibre 在
pixelRatio为 2 的设备上找不到@2x版本,图标会被跳过。
排查过程
先确认图片本身能否加载,再确认是否已注册到样式:
var img = new Image();
img.onload = function () { console.log('图片尺寸', img.width, img.height); };
img.onerror = function (e) { console.error('图片加载失败', e); };
img.src = '/icons/pin.png';
// 加载完成后检查是否注册成功
console.log('已注册图标', map.hasImage('pin'));
解决方案
用 map.loadImage 拿到 ImageBitmap,再 addImage。
两步都返回 Promise,确保顺序正确:
Promise.all([
map.loadImage('/icons/pin.png'),
map.loadImage('/icons/pin@2x.png')
]).then(function (images) {
map.addImage('pin', images[0].data, { pixelRatio: 1 });
map.addImage('pin', images[1].data, { pixelRatio: 2 });
}).catch(function (err) {
console.error('图标注册失败', err);
});
map.addLayer({
id: 'poi-icons',
type: 'symbol',
source: 'poi',
layout: {
'icon-image': 'pin',
'icon-size': 0.8,
'icon-allow-overlap': true
}
});
只有一个文件时,用 sdf 或 pixelRatio: 2 让高分屏复用同一张图:
map.loadImage('/icons/pin.png').then(function (image) {
map.addImage('pin', image.data, { pixelRatio: 2 });
});
资源路径统一走绝对路径,避免子路由下相对路径失效:
// 错误:./icons/pin.png 在 /project/detail 下会解析成 /project/icons/pin.png
// 正确:由构建变量注入基路径
var ICON_BASE = '/assets/icons/';
map.loadImage(ICON_BASE + 'pin.png');
验证
map.hasImage('pin') 为 true;
网络面板不再有 404;地图上每个点都显示图标。
把浏览器切到 2 倍像素比,图标仍然清晰,不出现空白方块。
顺序陷阱:addImage 必须在图层创建之前完成。
图层已经存在时补注册图标不会自动刷新,需要重新设置
icon-image 才会生效。
经纬志(2026)。《自定义图标全部 404,标记变成空白》。https://www.jingweizhi.com/cookbook/maplibre-icon-404.html(访问日期 2026-11-03)。