更换fontFamily后元素clientWidth获取值不准确问题咨询
问题原因
你遇到的宽度不匹配问题核心是自定义字体加载时序和DOM渲染时序不一致:
你引入字体时设置了display=swap,该配置会让浏览器优先使用系统 fallback 字体渲染文本,等Poppins字体加载完成后再替换重绘文本。mounted钩子仅代表Vue组件的DOM挂载完成,此时自定义字体大概率还未完成加载/替换,你拿到的是 fallback 字体渲染的宽度,等字体替换完成后元素实际宽度发生变化,就出现了数值不匹配的情况。即使是本地字体也存在文件加载、解析的时间差,不会在DOM挂载瞬间就完成渲染。
注意:你提供的字体引入代码存在语法错误,
rel="stylesheet缺少闭合双引号,修复后才能保证字体正常加载:<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap">
解决方案
方案1:使用Font Loading API监听字体加载完成后再获取宽度(最推荐)
浏览器原生提供的Font Loading API可以精准监听字体加载完成的时机,直接在回调中获取宽度即可保证数值准确:
<template> <div id="poppins" style="display: inline-block;">Item One a</div> </template> <script> export default { name: 'App', async mounted () { // 等待所有字体加载完成 await document.fonts.ready // 也可以指定监听特定字体加载完成,例如: // await document.fonts.load('16px Poppins') console.log(document.getElementById('poppins').clientWidth) } } </script>
方案2:调整font-display配置
如果你可以接受短暂的文本不可见,可以将字体引入中的display=swap改为display:block:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display:block">
该配置下,字体未加载完成时文本会隐藏,等字体加载完成后才会渲染,此时mounted阶段如果字体已经加载完成,拿到的宽度就是准确的。该方案缺点是网络差时会出现较长时间的文本空白。
方案3:全局控制内容渲染时机
如果需要保证全站所有自定义字体渲染完成后才展示内容,可以配合CSS实现:
首先在全局CSS中添加:
body { opacity: 0; transition: opacity .2s; } body.font-loaded { opacity: 1; }
然后在入口文件监听字体加载完成后添加类名:
document.fonts.ready.then(() => { document.body.classList.add('font-loaded') })
该方案下所有内容都会等字体加载完成后才展示,不存在字体切换的闪烁,此时任意阶段获取元素宽度都是准确的,缺点是首屏会有短暂的白屏时间。
内容的提问来源于stack exchange,提问作者Andrea Verrecchia
相关产品推荐
相关产品推荐

