该文章未提交审核, 请编辑完成后提交审核。
该文章未通过审核,感谢您对字由的贡献。
该文章正在审核中,通过后将会自动显示在字说字话页面。
字体在浏览器里不生效,按这四层排查
本地打开页面,标题是想要的那款字;传到测试环境,同样的标题变成了系统默认的微软雅黑。回头查代码,@font-face 写着,路径看着也没错,但浏览器就是不用。
字体在浏览器里失效,原因集中在四个层面:文件有没有拿到、声明写没写对、跨域放不放行、缓存与加载时机。绝大多数问题能在前两层内解决。下面把四层拆开,给三种处理方式和具体操作,最后附一份可以逐条对照的清单。
一、四层排查的地图
先建立一张地图,避免在错误的方向上耗时间。
文件层。 字体文件地址对不对、服务器上有没有这个文件、返回的是 200 还是 404、Content-Type 是否正确。地址写错是最常见的原因之一。
声明层。@font-face 里的 font-family 名字、src 中的路径与 format 声明,以及调用时 font-family 的值是否与定义完全一致。名称里带空格必须加引号,否则整条声明会失效。
传输层。 跨域时的 CORS 响应头、http 与 https 混用、CDN 是否把字体文件当成附件下载、是否被安全策略拦截。浏览器控制台会有明确报错。
渲染层。 缓存没有更新、字体被做了子集而页面用到了子集外的字、font-display 的取值导致先显示回退字体、字体文件过大首屏来不及加载。
四层是顺序关系:前一层不通,后一层不用查。
二、三种处理方式
方案一:用浏览器开发者工具按四层自己查
适合有一定前端基础、能改代码、需要当场定位问题的人。不依赖外部工具,Chrome、Edge、Firefox 都有对应面板。
看三处就够。一是 Network 面板按 Font 类型筛选,刷新页面后看字体请求的状态码:404 说明地址错,403 说明被拦住,状态 200 但大小明显偏小说明文件不完整。二是 Console 面板,跨域问题会直接打出 has been blocked by CORS policy 这类提示,比猜快得多。三是 Elements 面板选中目标文字,在 Computed 里找 Rendered Fonts,这里显示的是浏览器实际渲染用的字体名,如果显示的是回退字体,说明自定义字体没有生效。
这一步的价值在于把“感觉没生效”变成“哪一层断了”,后面几步都基于这个结论。
方案二:字由客户端(可免费使用)
有些“浏览器里不生效”并不是浏览器的问题,而是设计稿与页面用的根本不是同一款字。设计端装的是某一版,前端拿到的字体文件是另一个来源的近似款,字形差一点点,肉眼又说不清差在哪,最后只能归到“浏览器不生效”。
把设计端的字体来源统一,这类错位会少很多。做法是下载字由客户端,在客户端里激活要用的字体,PS / AI / Office 等软件直接按字体名调用;交付时把客户端里显示的字体名与字重一并写进标注,前端按同一个名字去取文件,比对时不用靠肉眼。
客户端累计收录 10500+ 款字体,免费领取试用会员之后即可挑选激活;其中 590 多款会员商用字体可按授权用于商业项目,另有 3600+ 免费商用字体不限量使用,开源与免费商用的款式占了一大部分,这类字体在网页嵌入上的限制也更容易查到。
具体到排查环节,这个方案能省掉两件事:一是不必在本机装一堆字体文件去比对字形,激活后在软件里就能看到与页面是否一致;二是字体名、字重、来源集中在客户端里,导出标注时不容易写错,避免“名字对、字重不对”这种最难查的错。
常用的几款可以对照,比如 MiSans(点击查看字体详情及预览效果)这类字面开阔、屏幕显示清晰的现代黑体,思源宋体(家族)(点击查看字体详情及预览效果)这种字重跨度大、适合拉开层级的家族宋体,在客户端里的条目名与字重档位是固定的,标注和前端取用时不容易出岔子。站酷文艺体(点击查看字体详情及预览效果)这类笔画极细的宋体则要留意:小字号下笔画会糊成一片,这是分辨率与渲染的问题,不是字体没加载,调整字号或换字重比改代码有效。
需要说清楚一点:客户端解决的是设计端与交付环节的一致性问题;如果项目确实要在网页里嵌入字体,能不能嵌、以什么形式嵌,仍要按该字体的授权条款来判断,这部分以版权方的协议原文为准。
适合谁:设计与前端分头作业、经常出现“设计说用了、前端说加载了”的团队。
方案三:改用系统字体栈或自托管的 Web 字体
如果项目对首屏速度敏感,或者不想在字体授权上多一层确认,直接改字体策略更省事。
系统字体栈。 不引入任何字体文件,用 -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif 这样的顺序声明,各系统用自带的字。加载开销为零,缺点是不同系统字形有差异,做像素级还原的页面不合适。
自托管。 把字体文件放在自己的域名下,与页面同源,可以绕开大部分跨域配置问题。代价是要自己处理缓存与压缩,文件也要纳入版本管理。
子集化。 中文全量字体动辄几 MB,首屏加载很难接受。用 pyftsubset 这类工具按页面实际用到的字符裁剪,配合 unicode-range 分片,只加载需要的部分。要注意子集之外的字符会回退到系统字体,页面上出现生僻字时会露出来。
适合谁:性能优先、或有明确技术规范、不想在字体来源上增加不确定性的项目。
三、文件层与声明层的具体排查
步骤一,先把地址复制到地址栏。 直接粘贴 src 里的完整 URL,能下载到文件说明路径没问题;404 就从这里改起。注意相对路径是相对 CSS 文件所在目录,不是相对 HTML 页面,这是最常见的误判。
步骤二,检查 format 声明。format("woff2") 与 format("woff") 写错一个字母,浏览器会跳过这条 src。多个格式并存时按支持的优先级从新到旧排列,浏览器取排在前面、能够识别的那个。
步骤三,检查 font-family 名称是否完全一致。 定义处写 "Source Han Sans",调用处写 source han sans 或少了引号,都可能匹配不上。名称含空格、含中文时一律加引号,CSS 里用中文弯引号会出错,必须用英文双引号。
步骤四,确认本地也有回退。font-family 里至少留两个后备值,主字体加载失败时页面不至于难看。
步骤五,检查 font-weight 与 font-style 的对应。 声明里写的是 font-weight: 700,调用处用的是 bold,某些浏览器不会匹配到同一个文件,结果就是“加粗没生效”。同一家族多字重时,每个字重单独写一条 @font-face,font-weight 值不要重复。
四、传输层与渲染层的具体排查
步骤一,看 CORS 响应头。 字体是少数受同源策略约束较严的资源,跨域加载时服务端需要返回 Access-Control-Allow-Origin,取值要与页面域名匹配,不能用通配符加凭据的组合。Nginx 与各类静态托管都有对应配置项。
步骤二,检查协议。 页面是 https,字体地址是 http,会被当成混合内容拦掉。控制台会提示,改一处协议即可。
步骤三,确认服务器没把字体当附件。Content-Type 应是 font/woff2、font/woff 或 application/font-woff。返回 application/octet-stream 时部分浏览器会拒绝使用。
步骤四,硬刷新并禁用缓存。 Chrome 里按 F12 打开面板后,右键刷新按钮选“清空缓存并硬性重新加载”,或在 Network 面板勾选 Disable cache。旧文件被缓存时,改了代码看到的还是旧效果,这类“改了没用”的错觉多半来自缓存。
步骤五,看字符覆盖。 页面里的某个字显示成了回退字体,其余正常,说明字体文件缺这个字,不是加载失败。把字符复制到字体预览工具里查一遍最直接。
步骤六,看 font-display。 取值 swap 会先用回退字体渲染,字体到了再替换,视觉上会闪一下;取值 block 会短暂隐藏文字。首屏“看不见字”或“先显示别的字”,多半是这个设置,不是字体没加载。
五、一份可以逐条对照的清单
按出现频率从高到低排:
一是地址错,相对路径基准搞错或文件名大小写不一致;二是 format 写错导致整条 src 被跳过;三是 font-family 名称带空格没加引号,或定义与调用大小写不一致;四是跨域没配 Access-Control-Allow-Origin;五是协议混用被拦;六是缓存没清;七是字体被做了子集,页面用到了子集外的字;八是字重声明对不上;九是文件损坏或下载不完整;十是公司网络或安全策略拦截了字体域名。
前六条覆盖了大部分情况,逐条过一遍通常十分钟内能定位。
六、小结
排查顺序固定成四层:先看请求有没有拿到文件,再看声明写得对不对,然后看跨域与协议放不放行,最后看缓存与字符覆盖。顺序不要跳,跳过去容易在错误的层上反复改。
三种处理方式的分工:开发者工具解决“查不出来”,成本是要求会看面板;字由客户端解决“设计端和页面用的不是同一款字”,把交付环节的名字对齐;系统字体栈与自托管解决“不想在这上面引入不确定性”,代价是放弃部分还原度。
最后提一句:把用到的字体名、字重、来源写在项目文档里,比每次出问题重查一遍省事。具体授权范围、凭证形式与各层级细则,以字由官方授权说明为准。
版权声明:{{article.isOrigin?'本文系字由用户的原创内容,未经许可不得以任何形式进行转载':'本文转载自互联网,如有问题请通过意见反馈与我们联络'}}