图标字体加载失败会留下无意义字符
别名: icon font · PUA · 图标字体 · tofu · ligature icons
概念解释
图标字体把图形编码成字体里的字形,通常放在私用区(PUA)或靠连字把字母序列替换成图标。字体没到、被拦截、子集里没有那一码,浏览器不会留下一块空白图,而会按普通字符回退:方框、tofu、空白、或作者当初当图标用的那个字母。对读屏,那是一个仍在文本流里的字符,会把码位或字母读出来。失败留下的是无意义字符,不是「图标没画出来」。
它处理的是图标字体这条失败形态,不是正文 FOIT/FOUT 的取舍,也不是中文正文要不要分片。
机制
文本布局把每个码位映射到当前字体的一个 glyph。PUA 码位在系统回退链里通常没有对应图形,于是出现 .notdef 方框或空白;若图标其实是 content: "\e001" 这类私用码,失败时屏幕上就是豆腐块。连字派把 content: "home" 或类名对应的字母画成房子图标,字体一失败,「home」或单个字母就以真文字出现在按钮里。无论哪一种,节点仍是文本:复制会得到怪字符,翻译工具会试图翻译它,屏幕阅读器按字符名称朗读,搜索会命中这些字母。
SVG、内联 path、<img> 的失败与此不同。图没加载可以不渲染、走 alt、或留下有尺寸的空位;它不向文本流注入一个码位。图标字体把「图形」寄生在文本管道里,所以文本管道的回退规则原样生效——而这套规则是为「缺字的语言」设计的,不是为「缺的是一张图」设计的。
边界
字体已缓存且从不更新的内部工具,失败率可以很低,但一旦 CDN 被拦、企业网络剥字体、用户开了「不允许远程字体」,字符立刻露出来。把图标字体只用于纯装饰且 aria-hidden 的场景,读屏噪音会小,视觉上的怪字符仍在。emoji 字体和系统符号字体走平台回退,缺的是另一套彩色字形,不是 PUA 豆腐,不要混为一谈。可变字体、子集化针对的是正文缺字和体积,修的不是「图标失败成字符」。CSS content 里的图标字符串在伪元素上,有的读屏会跳过伪元素,有的不会,不能当无障碍方案。
怎么落地
- 交互图标改用 SVG、内联 path 或带
alt/ 可访问名称的<img>;不要把可操作含义放进图标字体的码位。 - 若暂时仍用图标字体:每个图标节点提供文本替代(可见文字或
aria-label),并把装饰性码位aria-hidden="true";为字体失败准备font-display: optional仍不够——optional 失败一样留下字符。 - 禁止用字母连字当图标(失败会露出单词);禁止把 PUA 字符写进可复制、可翻译的正文。
- 验证:在开发者工具里禁用该字体或阻断其网络请求,看每个图标位置出现的是空白/替代图,还是方框、字母、可读出的码位。用读屏听失败态:不应读出「private use」或「home」这类字。复制按钮,剪贴板里不应出现怪字符。