
做地图这一行做了快十年前前后后跟瓦片谈过好几轮“恋爱”踩过不少坑也总结出不少经验。矢量瓦片vector tile和栅格瓦片raster tile这两个词几乎每个搞GIS、做WebGIS、搞大屏可视化的人都绕不开。你打开任何一个在线地图底层都是这两种瓦片在默默干活。很多刚入门的朋友跑来问我到底选哪个性能差多少为什么有人说矢量瓦片是未来可我看到很多项目还在用栅格这篇文章我就把这两种瓦片从头到尾掰开揉碎讲一遍从数据组织方式、渲染原理、体积对比、工具链到生产环境里的坑和选型建议一次说清楚。不管是刚接触地图开发的新手还是已经在项目里被瓦片方案折腾过的老手应该都能找到点有用的东西。1. 为什么会有两种瓦片从地图切图说起1.1 瓦片是什么为什么非得切成小块先回顾一个基础问题为什么地图非要切成“瓦片”你想啊一张覆盖全世界的地图如果做成一张完整图片那文件大小能上TB级别说浏览器加载不动单是打开本地文件都会卡死。所以主流方案就是“金字塔切片”——把地图按照不同的缩放级别zoom level切成无数个固定大小的小方块每个小方块就是一张瓦片。瓦片的编号规则通常是 z/x/yz 是缩放级别x 和 y 是行列号。Z级别每增加一级瓦片数量就变成原来的4倍。Z0 只有1张瓦片Z10 就到了大约100万张Z18 那就得按亿来算了。这样切换地图时浏览器只需要按需加载当前视野范围内的几十张瓦片其他区域等你拖过去再说体验就顺滑了。但“切成小方块”这件事切法不同得到的瓦片就分成了两大阵营栅格瓦片和矢量瓦片。1.2 栅格瓦片切出来的是一张张“图片”栅格瓦片本质上是图片。服务端预先用渲染引擎把地图画好输出成 PNG 或 JPEG 格式的小图存到磁盘或对象存储上。客户端拿到什么就显示什么拿到的就是一张已经包含所有颜色、文字、道路线的成品图。我举个例子你用过微信发照片吧发送前微信会先压缩对方看到的是压缩后的成品。栅格瓦片也是这样服务端已经把“怎么渲染”这件事做完了客户端只负责“展示”这一个动作没有任何二次加工空间。栅格瓦片最典型的就是影像底图比如卫星影像、航拍图还有那些带精细纹理的电子地图。只要数据本身是“连续面状信息”的栅格几乎是无脑首选。1.3 矢量瓦片切出来的是“数据包”矢量瓦片就完全不一样了。它切的不是图片而是几何数据。每一块瓦片里装的是道路、河流、建筑、POI点这些要素的坐标信息用高效二进制编码常见是 Protocol Buffers 的 .pbf 格式压缩起来。客户端拿到这个数据包后再根据当前视角用 GPU 实时把道路、文字、图块画出来。还是拿微信照片打比方矢量瓦片就像是你发给对方一个 PSD 源文件对方拿到之后可以自己调色、改字、加滤镜。你看到的样式完全取决于客户端怎么“渲染”这个源文件。所以矢量瓦片有一个栅格瓦片比不了的绝活同一套数据源可以实时切换不同的主题样式。白天模式、夜间模式、深色大屏模式、色盲友好模式切换样式只是一行代码的事根本不用重新切图。这就是为什么现在的三维城市、大屏可视化、实时路况这些场景越来越倾向于用矢量瓦片。你可能会问那是不是矢量瓦片全面碾压栅格还真不是。接下来我把各个维度拆开对比你就知道它们各自的地盘在哪了。2. 数据量对比为什么矢量瓦片能小上百倍2.1 我实测过的一组体积数据先说我实际生产环境里遇到的一组数。一个中等省份的矢量路网数据用 Mapbox 的矢量切片规范切到 Z14 级别最终生成的瓦片包大约只有 200 到 300MB但同样范围、同样级别的栅格瓦片如果包含道路、注记、POI 图标全要素渲染体积直接飙到 30 到 50GB。差了两个数量级。全球范围的对比更夸张。公开数据里OpenMapTiles 的全球矢量切片包到 Z14 左右大约 50 到 80GB而同等覆盖范围的栅格底图放大到能看清街道级别怎么也得几个 TB 起步。所以那些在线地图服务商绝大多数底层都是矢量切片方案就是因为他们扛不住栅格瓦片的存储和带宽成本。2.2 为什么体积差这么多栅格瓦片是“画好了再切”。每一张瓦片都包含完整的视觉信息背景颜色、道路线宽、文字阴影、图标纹理这些一旦渲染成图片就得全部存下来。而且不同缩放级别需要重新画、重新切每个级别都是独立的一套完整图片所以瓦片集合的体积是随级别增加呈指数级膨胀的。更关键的是栅格瓦片里绝大多数像素都是“无信息”的。一张 256x256 的底图瓦片可能 80% 的区域都是空白的背景色但 PNG 压缩算法照样要为这些空白像素付费。就算优化到极致也逃不开“图片存了多少像素就要花多少存储”这个物理定律。矢量瓦片则完全不同。它存的是“坐标点串”像一个点两个点一条线占用的字节数只跟要素的几何复杂度有关跟你在屏幕上画多大、用多粗的线、什么颜色完全没有关系。一条公路在 Z10 和 Z16 级别下几何数据可能都有但描述它的坐标点数量基本没变顶多在不同级别做了简化所以整体数据量增长远比栅格慢。2.3 矢量瓦片的数据简化技术矢量瓦片之所以能做到这么小还靠一个关键技术几何简化simplification和量化压缩。几何简化就是当缩放级别低的时候删除那些在屏幕上根本看不清的微小弯折。比如一条山路在 Z8 级别显示时可能只需要 20 个顶点就能画出来到了 Z14 级别道路的弯道清晰可见才需要 200 个顶点。Mapbox Vector Tile 规范里有个 quantization量化参数默认把瓦片内的坐标映射到一个 4096x4096 的网格上用一个 14 位整数表示坐标比直接用浮点数节省一半空间然后再用 Protocol Buffers 做一次紧凑编码。还有一个容易忽略的点矢量瓦片只在需要的级别存需要的要素。比如某些小字号的POI点在低级别直接就不存了只在高级别才出现。而栅格瓦片呢服务端渲染的时候虽然也能控制哪些要素显示但画出来的图片里那些看不见的要素并不会帮你省像素。注意矢量瓦片体积小是相对“全要素渲染的栅格瓦片”而言的。如果你把栅格瓦片做成只含背景和道路的简化底图不做任何注记体积也能压得很低。所以比较时要对等比较别拿“全要素栅格”和“极简矢量”比那不公平。3. 渲染方式与表现力谁更灵活谁更省心3.1 栅格瓦片服务端渲染客户端无脑显示栅格瓦片的最大优点是“所见即所得”。因为渲染发生在服务端用什么字体、什么颜色、什么线宽都是提前固定好的到了客户端就是一张图不存在跨平台渲染不一致的问题。这个特性在做离线地图、地质图、气象图这类对色彩准确性要求极高的场景时特别重要。比如土壤类型图、地质岩性图那些颜色都是行业标准规定的用户拿着图纸对比屏幕色差一点都会被投诉。这类需求用栅格瓦片绝对不会出错因为每个用户看到的都是同一张图片。栅格瓦片的缺点也来自这里样式完全锁死。你想换一种配色必须回到服务端重新渲染、重新切图、重新部署一次全量切片可能跑好几天。而且每个样式都要维护一套瓦片如果有多套样式日间/夜间/季节变换存储成本直接翻倍。3.2 矢量瓦片客户端实时绘制样式自由发挥矢量瓦片把渲染压力转移到了客户端。浏览器的 WebGL 或移动端的图形 API 拿到坐标数据后实时生成每个像素。这意味着你可以在用户交互的瞬间改变样式鼠标划过道路高亮、白天自动切浅色主题、晚上自动切深色主题都是毫秒级响应。做智慧城市大屏的时候我经常要在一个大屏上同时展示基础道路、实时路况、地铁线路、POI 标注、建筑轮廓。这几个图层如果全用栅格瓦片我得准备五套瓦片切换图层就是切换底图视觉上有割裂感。矢量瓦片可以同时加载一个基础底图剩下的路况、地铁、POI 都是动态叠加的数据层颜色、透明度、标注避让全部实时计算效果是栅格方案做不到的。不过灵活是有代价的。客户端渲染意味着字库、字体渲染方式不同会导致跨设备显示效果有细微差异。某个字体在你开发机上显示刚刚好在用户手机上就可能出现文字重叠或被截断。这类问题在低端安卓机上尤其明显做项目时一定要提前测试。3.3 三维场景下的碾压级优势还有一个栅格瓦片完全没办法比的场景三维地图3D Tiles / 倾斜摄影 矢量叠加。三维场景里相机可以倾斜、旋转栅格瓦片只能贴在平面上当“贴图”一但视角倾斜文字和图标就会被拉伸变形完全没有体验可言。矢量瓦片因为是矢量数据配合三维渲染引擎可以做到文字始终面向相机billboard效果、建筑按高度拉伸、道路随地形起伏贴合这些动效在智慧园区、数字孪生项目里是标配。我做过一个城市级的三维展示项目底图就是用矢量瓦片生成的建筑白模再叠加实时业务数据。客户看到后说“这比之前那张静态平面图高级太多了”其实本质差别就是数据从“图片”升级成了“活的几何”。4. 加载性能与体验传输、解码、渲染的博弈4.1 网络传输矢量瓦片更轻但首帧不一定更快单论网络传输矢量瓦片胜出。一个 256x256 的栅格瓦片就算简单底图也有 30 到 100KB矢量瓦片同样范围可能只有 10 到 30KB。加载同样一片视野区域矢量瓦片少传一半以上的数据在移动网络下体验差别很明显。但这里有个反直觉的点首屏渲染速度栅格瓦片反而可能更快。栅格瓦片拿到图直接贴上屏幕不需要解析几何、不需要计算样式浏览器几毫秒就能画出来。矢量瓦片拿到 .pbf 文件后要先解码坐标数据、构建渲染指令再提交给 GPU 绘制首帧耗时通常比栅格多几十到一百多毫秒。如果你的用户网络特别慢且设备又很老旧栅格瓦片反而感觉“更跟手”。所以做移动端低端机适配项目时我往往会采用“栅格瓦片出底图”的稳妥方案确保每个用户都能流畅看到图。而做高端展示、大屏、Web端可视化项目优先用矢量瓦片反正电脑和旗舰手机的 GPU 渲染能力完全罩得住。4.2 客户端设备适配老手机最怕矢量瓦片我在一个政企项目里测过一批老旧的国产平板大概五六年前的配置WebGL 性能很弱。同样的地图区域栅格瓦片加载流畅矢量瓦片一缩放就掉帧文字重绘还会闪。原因很简单栅格瓦片把所有渲染工作都丢给了服务端客户端只做一次图片贴图矢量瓦片把渲染压力分摊给了用户的 CPU 和 GPU设备太老就扛不住。更麻烦的是部分老设备对 WebGL 的支持不完整矢量渲染会出现奇怪的图形撕裂。遇到这种情况要么放弃矢量方案换回栅格要么给老设备单独准备栅格瓦片做“双轨降级”。这个属于架构层面的取舍得在项目初期就评估清楚别等上线了才发现问题。4.3 瓦片更新与实时性矢量瓦片能按需更新栅格得全量重切数据更新这块两者差距也巨大。栅格瓦片只要源数据有任何变化就得重新渲染而且因为瓦片之间存在样式连续性通常需要把影响范围内的所有级别全部重切一次更新动辄几小时甚至几天。矢量瓦片就灵活多了源数据变化后只需要重新生成受影响的那一层数据旧的瓦片还能继续用某些方案甚至支持局部瓦片更新。还有一个更高级的玩法矢量瓦片可以和前端数据流打通。比如实时路况数据不走瓦片而是通过接口下发给客户端客户端再覆盖在矢量瓦片上。但栅格瓦片想做到实时更新就必须持续重切图片成本高得多。所以如果你做的是交通调度、物流追踪、应急指挥这类数据变化频繁的系统矢量瓦片几乎是唯一合理的选择。底图保持静态业务数据动态覆盖成本和体验都能兼顾。5. 工具链与开发上手从切图到上线的全流程对比5.1 栅格瓦片的常用工具链做栅格瓦片工具选择比较成熟门槛相对低。QGIS免费开源自带切片导出功能适合做小范围、简单样式的瓦片。操作界面友好新手一天就能上手。MapTiler Desktop商业软件但桌面版有免费额度。能把各种格式的GIS数据转成瓦片内置样式模板很多出图效果好适合快速出成品底图。ArcGIS Pro老牌商业GIS平台切片能力很稳适合已有 ArcGIS 生态的企业团队。GDAL2Tiles命令行工具脚本化批量处理神器适合CI/CD流程里自动化出瓦片包。栅格瓦片的输出格式就是一堆图片文件按照 z/x/y 的目录结构摆放。也可以打包成 .mbtilesSQLite 数据库格式部署时再通过瓦片服务把里面的图片读出来。后端服务器上用 Nginx 直接 serve 静态文件或者用 MapProxy、GeoServer 这类瓦片服务中间件都很方便。5.2 矢量瓦片的常用工具链矢量瓦片工具链相对新一些但生态也已经比较成熟了。tippecanoeMapbox 开源的矢量瓦片切片工具命令一行搞定tippecanoe -o output.mbtiles input.geojson。它对数据做了很多优化比如按要素密度分级、自动简化几何、丢弃看不到的细节生成的瓦片体积非常小。我用它切过一个全国路网数据输出简直让人惊喜。Mapbox Studio / MapLibre Studio可视化样式编辑器可以导入矢量瓦片元数据拖拽式设计配色、文字、图标。MapLibre Studio 是开源替代品适合不能使用 Mapbox 商业服务的团队。OpenMapTiles开源的企业级地图方案提供了从 OpenStreetMap 数据到矢量瓦片的完整处理管道。还提供可以免费下载的全球瓦片包省去自己切图的功夫。PostGIS 自研切片如果你有特殊需求比如要把业务数据和基础地图一起切片可以用 PostGIS 做空间运算再写脚本生成矢量瓦片。这种方案学习成本高但自由度最大。矢量瓦片前端渲染库主要有 MapLibre GL JS开源兼容 Mapbox GL 规范、Mapbox GL JS商业授权、OpenLayers近几年加入了对矢量瓦片的支持、CesiumJS三维场景下用矢量瓦片。其中 MapLibre GL JS 是目前我比较推荐的开源选择从 Mapbox GL JS 分叉而来API 几乎一致迁移成本低。5.3 一条我觉得稳的全流程路线这些年我比较推荐的路线是用 tippecanoe 把数据切成 .mbtiles 格式的矢量瓦片包部署时再用 Martin一个轻量级瓦片服务器Rust 写的性能很好把 .mbtiles 直接发布成 HTTP 服务前端用 MapLibre GL JS 加载并定义样式。这条链路全开源、无版权坑、性能也完全够用。我实际测试过一个 40GB 的路网数据tippecanoe 切片大概跑了 20 分钟最后生成的 .mbtiles 只有 1.2GB。Martin 发布后打开页面首屏加载速度基本在 1 秒以内本地局域网环境。相比之前用 GeoServer 发布栅格瓦片等待时间缩短了非常多。6. 常见问题排查与避坑经验6.1 矢量瓦片常见问题速查现象可能原因解决办法文字闪烁、跳动缩放级别切换时标注重复或避让算法不够好开启样式里的碰撞检测和重复标注合并或者使用全局标注模式低级别下小要素丢失tippecanoe 的 drop-rates 参数把低级别要素删掉了调整切片参数减少删除率或者把最小显示级别调高中文字体模糊字库没有嵌入或者使用了系统默认字体在样式里显式指定带中文字形的字体必要时使用 PBF 字体文件高DPI屏下标注模糊渲染分辨率不足开启 devicePixelRatio 适配让渲染在2x分辨率下进行跨平台颜色不一致不同设备对透明度和抗锯齿处理方式不同统一测试设备尽量使用同一种浏览器内核6.2 栅格瓦片常见问题速查现象可能原因解决办法瓦片边界有明显接缝切片时抗锯齿设置不当或图幅边缘处理问题检查切片工具的抗锯齿选项试试加1像素的羽化过渡缩放时图片模糊然后清晰只切了部分级别浏览器在拉伸拼凑补全金字塔里的瓦片级别特别是低级别的大比例尺瓦片背景色瓦片特别大空白区域被当成有损压缩的内容处理对纯色区域使用 PNG 而不是 JPEG或用透明底色加 WebP更新瓦片后用户还看到旧图HTTP 缓存未失效发布时给瓦片 URL 加版本号参数并配置 Cache-Control 头加载速度越来越慢瓦片切得太多太碎单张图片偏大适当提升瓦片压缩率或换 WebP 格式6.3 我踩过的几个典型坑先说一个特别坑的事。有一次做一个全国范围的可视化项目我图方便直接下载了某个第三方平台的全球栅格瓦片包部署到内网之后发现部分地区的文字和边界有严重偏移。排查到最后才发现是投影坐标系不对——平台默认用了 Web墨卡托的投影规则而我内网的系统里用了经纬度直投的方式。这里提醒一句瓦片从一开始就要统一投影标准否则后期会非常多坑。再说矢量瓦片的问题。有一次前端同事那边报告说缩放地图时文字一直跳动看着特别难受。我排查了很久最后发现是样式文件里的文字字段没开启碰撞检测collision detection导致同一个POI在相邻级别里重复渲染前一个还没完全消失后一个就出现了。解决办法是把样式里的 symbol-placement 从 point 改成 line-center或者打开 allow-overlap 的相反开关文字才稳定下来。还有一个容易踩的坑是矢量瓦片的“密度陷阱”。某些区域POI特别密集切成矢量瓦片后单块数据可能大到几百KB反而比栅格瓦片还大。这时候必须在切片之前做数据抽稀按照不同级别控制要素数量上限。tippecanoe 的 -r1强制最低级别密度和 -B 参数就是干这个用的。6.4 选型决策到底该用哪个最后聊一下项目选型这也是我收到私信最多的一个问题。没有万能的答案但有一些判断标准可以参考如果你做的是标准电子地图、导航地图、类似在线地图的产品优先考虑矢量瓦片。体积小、更新灵活、样式自由优势非常明显。如果你做的是影像地图、扫描地图、地形图、地质图这类颜色就是信息核心的场景用栅格瓦片。不仅省事而且能保证显示效果和原图完全一致。如果你的用户里存在大量老旧设备比如政企项目的存量平板优先用栅格瓦片或者做双轨降级方案别让渲染性能拖垮体验。如果项目周期很紧、前期没有专职GIS工程师栅格瓦片上手更快因为工具成熟、踩坑少。如果项目要做长期运营数据会持续更新那就尽早切换到矢量瓦片因为栅格瓦片的更新时间成本会越来越让人崩溃。我个人在实际操作里的体会是大型项目基本都会采用“矢量底图 栅格影像”的混合方案。基础道路和注记用矢量瓦片卫星影像和业务底图用栅格瓦片。两者配合既能享受矢量瓦片的轻量和灵活又能保住影像的真实感这才是绝大多数生产环境的真实形态。最后的最后再分享一个小技巧不管用哪种瓦片上线前一定做一次“弱网 低端机”双体检。Chrome 开发者工具里把网络切成 Slow 3G再开一台两年前的安卓真机跑一遍核心路径。你会发现很多在开发机上感觉不出来的问题在这个组合下全暴露了。这些问题宁可上线前解决别等客户截图发群里再改。