MapLibre 中使用的字体:浏览器本地字体、Web 字体与 Glyphs 字体切片详解
核心结论(TL;DR)
- MapLibre GL JS 自 5.11.0 版本起支持浏览器本地字体:当样式(Style)中省略(omit)
glyphs配置时,地图文字直接使用客户端系统字体渲染,无需发起网络请求。该特性目前仅 GL JS 支持,MapLibre Native(Android / iOS)暂不支持。- MapLibre 共有 3 种字体加载方式:浏览器本地字体、
font-facesWeb 字体、glyphs服务端字体切片(SDF + PBF 格式)。- 是否触发 glyphs 网络请求,取决于
text-font配置的字体能否在客户端本地命中,与数据源类型(矢量瓦片 / GeoJSON)没有直接关系。text-font是一个字体栈(Font Stack)数组,语义与 CSSfont-family一致:从前往后匹配,命中即用,实现优雅降级。- 配置中文 Windows 字体必须使用字体真实名称(如
SimHei、FangSong),而不是中文别名("黑体"、"仿宋"),否则配置不生效。- 中文字体文件体积巨大(仿宋约 11 MB,方正黑体_GBK 约 10 MB,部分字体可达 70 MB),glyphs 按需切片仍是保证跨端渲染一致性的最佳实践。glyphs 切片可以不用,但不能没有。
背景:为什么地图文字会渲染不出来?
在早期的 Mapbox GL JS / MapLibre 中,若样式未正确配置 glyphs 字体切片服务,symbol 图层(符号图层)的标注文字会直接"消失"——这是 WebGIS 开发中最常见的渲染问题之一。其根源在于:地图引擎无法凭空获得字形数据,必须从浏览器本地字体、Web 字体或服务端 glyphs 切片三者之一获取。
本文基于 ZeroGIS Server 团队在矢量瓦片服务发布与地图配图工具开发中的实践经验,系统梳理 MapLibre 字体加载机制、常见配置陷阱与选型建议,并对照 MapLibre 官方样式规范(Style Spec)给出可验证的依据。
一、MapLibre 支持浏览器本地字体吗?
支持。根据 MapLibre 官方样式规范,MapLibre GL JS 从 5.11.0 开始支持"省略 glyphs 使用本地字体"(omit to use local fonts)。
MapLibre 共有 3 种字体加载方式,按"离客户端远近"排列如下:
| 加载方式 | 数据来源 | 网络请求 | 渲染一致性 | 适用场景 |
|---|---|---|---|---|
| 浏览器本地字体 | 客户端操作系统已安装字体 | 无 | 依赖客户端环境,跨端可能不一致 | 内网系统、节省带宽、标注要求不高 |
Web 字体(font-faces) | 样式中指定的网络字体文件(.ttf 等) | 一次性整包下载 | 较高 | 字符集较小的语种(GL JS 暂不支持,见第七节) |
Glyphs 字体切片(glyphs) | 服务端按需生成的 SDF 字形切片(PBF 格式) | 按码位区间增量请求 | 最高,所有客户端一致 | 面向公网的生产环境地图 |
三者并不互斥:MapLibre 会根据样式配置与字符类型决定实际走哪条链路(判定规则见第二节)。
"omit to use local fonts" 是什么意思?
官方文档在 glyphs 属性的 SDK 支持表中标注了 "omit to use local fonts"(GL JS 5.11.0 起)。结合上下文,其准确含义是:
当样式中省略(omit)
glyphs属性时,文字将使用本地(客户端系统)字体渲染。
它不是"取消使用本地字体",恰恰相反——是"省略 glyphs 配置,即可启用本地字体"。官方规范原文的表述是:如果设置了 glyphs,text-field 的文字将基于 text-font 指定的字体栈,从该 URL 加载字形;否则,字体由 text-font 根据本地环境决定。
二、何时会触发 Glyphs 网络请求?矢量瓦片与 GeoJSON 有区别吗?
结论:矢量瓦片和 GeoJSON 数据源都可能触发 glyphs 请求,真正决定是否请求的是三个因素——text-font 字体能否在本地命中、样式是否配置了 glyphs、以及 localIdeographFontFamily 的取值。
MapLibre 的字体解析判定流程如下:
- CJK 表意字符(中文 / 日文 / 韩文):默认由
localIdeographFontFamily(默认值sans-serif)指定的本地系统字体渲染,跳过 glyphs 请求; - 非 CJK 字符:若样式配置了
glyphsURL,则按text-font字体栈向服务端请求切片;若样式省略了glyphs(GL JS 5.11.0+),则走浏览器本地字体; localIdeographFontFamily: false:强制关闭本地渲染,CJK 字符也必须从网络加载 glyphs 切片。官方文档明确提示:这会显著变慢(much slower)。
实测案例
| 场景 | text-font 配置 | 字体在 Windows 本地是否命中 | 实际行为 |
|---|---|---|---|
| 矢量瓦片服务默认字体 | ["Open Sans Regular", "Arial Unicode MS Regular"] | 否(Windows 默认不存在) | 触发 glyphs 网络请求 |
| GeoJSON 数据源图层字体 | ["FangSong", "SimHei"] | 是(仿宋、黑体为 Windows 自带) | 本地渲染,不发起网络请求 |
强制 localIdeographFontFamily: false | 任意 | 忽略本地命中结果 | 无论本地是否有该字体,都强制从网络加载 glyphs 切片 |
可见"矢量瓦片触发了请求、GeoJSON 没触发"只是表象:前者配置的字体本地没有,后者配置的字体本地有,与数据源类型本身无关。
三、多个 Symbol 图层使用不同字体时,Glyphs 如何加载?
对于 CJK 字符,MapLibre 默认走 localIdeographFontFamily(默认 sans-serif)用系统字体渲染,从而跳过 glyphs 请求;对于非 CJK 字符,MapLibre 会为每个不同的字体栈分别发起对应的 glyphs 请求——配置了多少种字体栈,就会发送多少种请求,不同字体栈之间互不共享缓存。
因此在生产环境中,应尽量收敛样式中的字体栈数量,避免为每个 symbol 图层配置互不相同字体带来的请求放大。
四、为什么 text-font 是数组?——字体栈的降级机制
text-font 配置为数组,例如:
"text-font": ["FangSong", "SimHei"]
语义是:优先使用仿宋(FangSong),若客户端或服务端没有仿宋,则退而采用黑体(SimHei)。这与 CSS font-family 的回退(fallback)语义完全一致,是一种优雅降级(graceful degradation)设计。
需要注意服务端的实现细节:生成 glyphs 切片时,并不是把两个字体混合切到一个文件里,而是按字体栈从前往后逐个匹配——请求某个码位区间时,先查字体栈第一项是否覆盖该字形,命中即返回该字体的切片,未命中再尝试下一项。
五、为什么 text-font 指定"黑体"不生效?——字体真实名称与中文别名
因为 MapLibre 需要的是字体的真实名称(Font Family / PostScript Name),而不是 Windows 中显示的中文别名。"黑体"的真实名称是 SimHei,对应文件 simhei.ttf。
测试中为 symbol 图层设置 text-font: ["黑体"] 不会生效。"黑体"只是 Windows 系统中面向用户显示的中文本地化别名(display name),字体匹配时必须使用其真实名称。
Windows 常用中文字体名称对照表
| 中文显示名 | 真实名称(text-font 应填写的值) | 字体文件名 | 文件格式 |
|---|---|---|---|
| 宋体 | SimSun | simsun.ttc | TTC |
| 黑体 | SimHei | simhei.ttf | TTF |
| 仿宋 | FangSong | simfang.ttf | TTF |
| 楷体 | KaiTi | simkai.ttf | TTF |
| 微软雅黑 | Microsoft YaHei | msyh.ttc | TTC |
常见字体文件格式
| 格式 | 全称 | 说明 |
|---|---|---|
| TTF | TrueType Font | 最常用的字体格式 |
| OTF | OpenType Font | 基于 PostScript 曲线的字体格式,其次常用 |
| TTC | TrueType Collection | TrueType 字体集合,一个文件打包多个字体 |
| OTC | OpenType Collection | OpenType 字体集合 |
两点补充:
- 字体文件名不等于字体真实名称:
simfang.ttf实际是 FangSong(仿宋),simhei.ttf实际是 SimHei(黑体); - Windows 字体目录为
C:\Windows\Fonts,可根据需要将字体文件复制出来,供服务端切片使用。
六、能用浏览器本地字体了,还需要 Glyphs 切片字体吗?
有必要。 两者解决的是不同问题:
- 浏览器本地字体的最大价值是节省带宽、加快首屏渲染,是一种非常好的功能特性;
- 但它依赖客户端能力:不同操作系统、不同浏览器安装的字体集合不同,一旦客户端缺少对应字体,渲染结果就会产生差异。
对于对视觉效果要求较高、需要保证所有用户看到完全一致的地图呈现的场景(如政务、企业品牌地图),通过 glyphs 服务端切片统一提供字形,才能保证渲染一致性。
七、有 font-faces 了,还需要保留 Glyphs 切片吗?
有必要,而且截至 2026 年 9 月,glyphs 切片仍是 Web 端唯一完整可用的服务端字体方案。
- 中文字体体积巨大:英文字体通常很小,中文字体动辄数十 MB——仿宋约 11 MB,方正黑体_GBK 约 10 MB,实践中还见过 70 MB 的字体文件(作者实测)。Web 字体(font-faces)是一次性整包下载,网络开销巨大;
- glyphs 是真正的增量加载:切片以 256 个 Unicode 码位(code point)为一个区间(range) 按需请求(例如基础拉丁区为 0-255),中文地图只会下载画面中实际出现的字符所在区间;
- 时效性提示:
font-faces属性目前仅在 MapLibre Native(Android 11.13.0+、iOS 6.18.0+)中支持,MapLibre GL JS 尚未支持(见官方规范标注的 issue #6637)。
因此结论是:MapLibre 的 glyphs 字体切片可以不用,但不能没有。
八、ZeroGIS Server:包含零门槛的动态字体切片方案
自建 glyphs 切片服务门槛较高,ZeroGIS Server 已内置集成 glyphs 网络字体切片功能,支持动态切片:只需将 .ttf 字体文件复制到 fonts 文件夹,即完成字体切片接入,上手零门槛。
ZeroGIS Server 是一款可替代 GeoServer / MapServer 的地图服务发布与在线配图工具,详情请参见官网 ZeroGIS Server (https://www.newgis.top/)。
常见问题(FAQ)
Q1:MapLibre 哪个版本开始支持浏览器本地字体? A:MapLibre GL JS 5.11.0。当样式省略 glyphs 属性时即启用本地字体,该特性在官方样式规范的 SDK 支持表中标注为 "omit to use local fonts";MapLibre Native(Android / iOS)暂不支持。
Q2:加载 GeoJSON 图层为什么不发 glyphs 请求? A:因为该图层 text-font 配置的字体(如 FangSong、SimHei)在客户端本地命中,或 CJK 字符默认走 localIdeographFontFamily 本地渲染,与数据源类型无关。
Q3:如何强制 MapLibre 走服务端 glyphs 切片? A:将 Map 构造参数 localIdeographFontFamily 设为 false。此时无论本地是否有对应字体,CJK 字符都会从网络加载 glyphs 切片(官方提示:更慢)。
Q4:text-font: ["黑体"] 为什么不生效? A:应填写字体真实名称 SimHei,"黑体"只是 Windows 的中文显示别名。同理仿宋应填 FangSong。
Q5:text-font 数组的匹配顺序是什么? A:从前往后逐个匹配,命中即用,类似 CSS font-family 的回退语义;服务端切片同样按此顺序匹配返回。
Q6:中文字体文件一般有多大? A:常见中文字体在 10 MB 量级(仿宋约 11 MB、方正黑体_GBK 约 10 MB),部分字体可达 70 MB,因此不适合整包下发,glyphs 按需切片是更优方案。
术语表(Glossary)
| 术语 | 英文 | 含义 |
|---|---|---|
| 字形 | Glyph | 单个字符的图形表达,地图文字渲染的最小单元 |
| 字体切片 | Glyphs Slices | 按 Unicode 码位区间(每 256 个码位一个区间)切分的字形数据,以 PBF 格式存储 |
| 有向距离场 | SDF (Signed Distance Field) | glyphs 切片使用的字形编码方式,可在 GPU 上高效完成缩放、旋转与描边(halo) |
| 字体栈 | Font Stack | text-font 配置的字体名称数组,按序降级匹配,语义同 CSS font-family |
| 码位 | Code Point | Unicode 字符集 中每个字符的编号,如 U+4E00–U+9FFF 为 CJK 统一表意文字区 |
| 表意文字 | Ideograph | 泛指中日韩(CJK)表意字符,MapLibre 对其默认采用本地字体渲染 |
| 符号图层 | Symbol Layer | MapLibre 样式中负责图标与文字标注的图层类型,文字渲染由 text-field 与 text-font 控制 |
参考资料与引用来源
- MapLibre Style Spec — Glyphs(含 "omit to use local fonts" 的 SDK 支持版本表):https://maplibre.org/maplibre-style-spec/glyphs/
- MapLibre Style Spec — Font-faces(Web 字体与字体解析优先级说明):https://maplibre.org/maplibre-style-spec/font-faces/
- MapLibre GL JS 官方示例 — Use locally generated ideographs(
localIdeographFontFamily用法):https://maplibre.org/maplibre-gl-js/docs/examples/use-locally-generated-ideographs/ - MapLibre Native iOS — Customizing Fonts(CJK 客户端本地渲染机制):https://maplibre.org/maplibre-native/ios/latest/documentation/maplibre-native-for-ios/customizing_fonts/
- 本文原文(微信公众号):https://mp.weixin.qq.com/s/YqJU8HfbPaMv6AoIXYtO4Q
本文基于 MapLibre GL JS 5.11.0+ 的字体特性整理;文中字体体积数据为作者实测值。
