如何避免由 Web 字体引起的布局偏移
2022-11-14 18:52:41来源:前端南玖
一些布局上的完全加载前后的变化很容易解决:为动态元素预先分配正确的空间,在图像上使用宽度和高度属性,并优先考虑 HTML 文档中的可见元素。但是,导致布局偏移的还有一个难以解决的问题:无样式文本 (FOUT) 的闪烁。
(资料图片仅供参考)
这篇文章我们将探索令人惊讶的复杂文本渲染世界,以及一些解决无样式文本闪烁的技术。
为什么字体会导致布局变化?意外的布局变化(页面内容在没有用户交互的情况下移动)不利于用户体验。下载网络字体时,当字体题发生变化时,会导致包含元素(例如
「两种不同的字体是可能会导致布局发生变化的,但不是一定,这主要取决于字体的字体高度。」
如何避免我们现阶段的网页为了满足用户的审美往往会使用一些特殊字体,但与此同时也会带来一些体验上的问题,最常见的就是页面的加载速度以及文本闪烁等。所以我们有必要对字体进行一些优化操作来满足我们“日益挑剔”的用户。
font-display最粗暴的解决方案是只需要一行CSS代码就能够解决。
font-display: optional;
为什么说只需要这一行代码就能够解决呢,因为如果 Web 字体在呈现文本时不可用(加上 100 毫秒),它会告诉浏览器使用备用系统字体。这意味着在未缓存的页面加载时,可能会使用备用字体,但所有后续页面加载都应使用 Web 字体呈现,因为它将被下载并在缓存中可用。
它一共有以下几个属性:
「auto:」字体显示策略由用户代理「block:」为字体提供一个短暂的阻塞周期和无限的交换周期,在等待网络字体时隐藏文本最多三秒钟,并在加载时始终交换网络字体「swap:」为字体提供一个非常小的阻塞周期和无限的交换周期,尽快显示文本,并在加载时始终交换网络字体「fallback:」为字体提供一个非常小的阻塞周期和短暂的交换周期,隐藏文本最多 100 毫秒,然后仅在三秒内加载时交换网络字体「optional:」为字体提供一个非常小的阻塞周期,并且没有交换周期,隐藏文本最多 100 毫秒,然后仅使用可用的网络字体,从不交换上面这样解释如果还不太明白的话,可以看看下面这张图:
「Optional 是唯一保证不发生布局偏移的字体显示值」
不幸的是,系统字体不一定是最好的设计,并且它们在各个操作系统之间并不一致。大多数设计师一想到向用户展示一个备用系统字体就会畏缩。接下来介绍各种优化以更快地将字体文件传送到浏览器,允许使用任何字体显示选项,但显示系统字体的风险最小,或者用于optional: 以外的选项而不触发布局转换。
优化字体文件优化网络字体有两种关键方法:子集和格式。
子集字体许多字体将具有来自多个字母的字形(字形是单个字符,例如a或&)如果你仅以拉丁字母 (a - Z) 提供并且不使用连字(如é),那么这些字形表示您的字体文件中浪费的字节。
从此字体中删除非拉丁字符会产生woff2一个大小为六分之一的文件。
字体格式各主流设备基本都支持 woff2 字体格式,因此网站中没有必要再引入多种不同格式的字体了。一般地,建议只引入 woff2 就好了,既可以保持代码的简洁性,又可以减少上传到你服务器的文件。
加载更少的字体虽然我们会将字体转换成woff2格式,但文件大小依然有好几百K,有时甚至是几M,字体文件的大小也会影响页面整体的渲染速度。有些时候我们只需要一些极少数的文字用于特殊字体,那我们就没必要将一整个字体文件引入了。
提取字体当我们遇到上面这种情况时,千万不要将一整个字体包引入进去,这将极大地浪费网络带宽,从而影响页面的加载。这里推荐使用font-spider 字蛛来提取文字。
安装font-spidernpm install font-spider -g提取
我们还是以上面那段诗句为例,那里我们用的是汉仪旗黑.woff2字体文件。这里还是经过缩小文字库之后的大概是32K
我们再在项目目录下执行以下命令
font-spider index.html
这时会生成一个.font-spider目录,并将提取后的字体文件放在该目录下。现在的字体文件大概就只有10K,比之前的体积小了好几倍。
使用系统字体Web 字体很受欢迎,因为它们允许设计人员在浏览器中保持一致的外观和感觉。如果不需要,系统字体将是呈现文本的最快方法。如果当前的Web字体接近系统字体,您可以使用Monica的Font Style Matcher来调整字体设置,直到获得近乎完美的匹配。
使用系统字体意味着文本将尽可能早地呈现。我们现在还拥有使字体与操作系统匹配的方法,这可能比以前的备用选项(如 Arial 和 Helvetica)更具吸引力。为此,我们需要按特定顺序列出所有操作系统的系统字体:
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;}快速交付字体文件
很明显,我们为了确保字体快速且正确地应用在我们网页上,我们必须让浏览器尽快下载我们的字体文件,在我们自己的CDN上托管字体将获得最佳性能。
使用CDN托管一般来说,我们应该提供我们服务器中的字体以避免连接到第三方服务器的成本,这对于高延迟连接尤其重要。使用第三方服务意味着您的字体将被延迟。最好的情况是您直接从另一个主机名(例如fonts.gstatic.com)请求字体文件,这会产生连接成本——DNS 查找、TCP 连接和 TLS 协商。最坏的情况是多跳,例如从fonts.googleapis.com加载引用fonts.gstatic.com上的文件的 CSS 文件,会导致两次连接损失。所以我们一般会将一些字体文件等静态资源托管在我们自己的CDN服务器上,以此来加快资源的下载速度。
缓存字体字体可以缓存在两个地方:「客户端和CDN」。客户端上的缓存对于会话中的导航很重要,并且应该以避免重新验证请求的方式完成。重新验证请求 (if-not-modified和if-modified-since) 将阻止浏览器使用字体文件,直到它验证它在服务器上没有更改。字体很少改变,所以我们应该如下实现一个缓存头,并在字体改变时更新文件名来破坏缓存:
cache-control: max-age=31536000,immutable
这告诉浏览器他们可以保留字体长达一年并且不需要重新验证( Firefox 和 Safariimmutable支持,Chrome 应该自动避免重新验证请求)。避免将 ETag 添加到这些响应中,因为它们可能会强制重新验证。
还要检查您的 Content Delivery Network 配置是否可以将字体文件存储在缓存中,较旧的配置可能不包含.woff2扩展名,从而导致原始命中并减慢响应速度。
使用预加载一般来讲浏览器不会随便地去下载字体文件,它们会等到渲染树构建完成后才能知道需要哪些字体。这意味着仅在浏览器下载并解析 HTML 和 CSS 时,即在呈现文本之前,才请求 Web 字体。「但需要注意的是,内联 CSS 不需要网络请求,这意味着我们的字体可以在页面加载的早期获取。」
渲染树的构建过程会阻塞Web字体的请求。
但是如果我们确定页面文本的渲染肯定会用到一些网络字体时,我们可以使用preload让浏览器提前下载字体文件。
当浏览器解析这行 HTML 时,它会立即发送一个对字体文件的高优先级请求。
「但是需要注意的是,预加载的请求会占用其它请求的带宽,所以我们在使用过程需要考虑清楚是否值得这么做。」
将字体转为Base64还有一种常用的方法是将字体作为 Base64 字符串嵌入到 CSS 中,从而无需额外的字体请求并确保在呈现文本时字体可用。
但这个方法也不是绝对的好方法,它只适合一些小型字体文件,例如上面提到的使用font-spider提取后的字体文件,并且该字体文件足够小,因为将字体文件转化为Base64字符串往往会增加体积。
一般来讲它有以下缺点:
字体文件是压缩的二进制对象,编码为 Base64 字符串会显着增加大小。CSS 包的 gzip 或 brotli 压缩并不能完全弥补这种膨胀。字体将被发送到每个浏览器,即使有的浏览器不能使用字体很少更改,但 CSS 经常更改,这将降低字体的缓存效率,因为每次 CSS 更改都会使整个包无效膨胀 CSS 大小几乎肯定会延迟页面渲染使用f-mods减少布局偏移F-mods 是对字体描述符规范的提议更新,其中包括四个新的描述符:
「ascent-override (%)」: 覆盖分配给上升器的大小「descent-override (%)」: 覆盖分配给下降者的行高「line-gap-override (%)」: 覆盖行间距「advance-override (#)」: 为每个字符设置一个额外的提前量,以帮助匹配行宽并防止单词溢出前三个都影响线的高度:线框高度 = 上升 + 下降 + 线间隙。基线位置 = 线框顶部 + 线间隙 / 2 + 上升。
这四个描述符的组合允许我们通过告诉浏览器在下载 Web 字体之前字符将占用多少空间来覆盖备用字体的布局以匹配 Web 字体。
f-mods只真正修改垂直间距和定位。这意味着仍然需要处理字符间距和字母间距,否则可能会在不同的点出现断行的单词,从而导致元素高度发生变化,从而导致布局发生变化。但是@font-face 声明中没有letter-spacingandword-spacing属性,因此我们必须在主体或元素上声明。
@font-face { font-family: custom-font; src: url("./public/fonts/汉仪旗黑.woff2");}@font-face { font-family: fallback-font; src: local(Arial); ascent-override: 100%; descent-override: 20%; line-gap-override: normal; advance-override: 10;}/* 这些具体数值因字体而已,需要按照自己的字体进行计算调整*/body { font-family: custom-font, fallback-font;}.content { letter-spacing: -1.1px; word-spacing: -0.2px;}总结
总之,如果浏览器没有及时获取网络字体,并且可以应用font-display: optional到网络字体,让浏览器以备用系统字体呈现来防止布局偏移,否则的话就只能优化我们的字体以尝试在浏览器需要它们之前将它们获取到浏览器:
使用woff2最小化文件大小优化字体文件加载更少的字体预加载关键字体在CDN上托管字体文件使用 f-mods 减少字体交换的影响相关新闻
如何避免由 Web 字体引起的布局偏移
前言一些布局上的完全加载前后的变化很容易解决:为动态元素预先分配正确的空间,在图像上使用宽度和...
世界杯应用程序带来数据安全和隐私噩梦
鉴于数以万计配备人脸识别技术的监控摄像头被强制要求下载间谍软件,下个月将在卡塔尔举行的世界杯看起...
删除的文件果真消失了吗?
数据销毁方法有很多种,但许多此类方法存在可以使数据恢复的漏洞。在选择擦除还是删除时,您需要了解为...
首席信息官如何保护企业免受云中断的影响
无论云计算供应商的服务器是否停机还是糟糕的服务性能违反了客户的服务等级协议,云中断都可能严重影响...
Stable Diffusion采样速度翻倍!仅需10到25步的扩散模型采样算法
要说AI领域今年影响力最大的进展,爆火的AI作图绝对是其中之一。设计者只需要输入对图片的文字描述,就...
人工智能导致可怕的网络安全威胁的三种方式
人工智能技术正在推动数字技术的一些巨大变化。人工智能带来的许多发展都是有益的。然而,人工智能同时...
我们一起聊聊可扩展 CSS 的演变
大家好,我是CUGGZ。自Web诞生以来,我们编写和思考CSS的方式发生了巨大变化。从基于table的布局到响应...
约克大学:AI进步很快,但它的识别能力比人眼还是差远了
深度卷积神经网络(DCNN)看待物件的方式与人类不同,约克大学教授JamesElder的研究团队认为,深度学习...
前端必懂的设计模式-门面模式
1 定义外观模式(FacadePattern)又叫门面模式,指提供一个统一的接口去访问多个子系统的多个不同的接口...
你问这谁会啊?ThreadLocal 父子线程之间该如何传递数据?
忘记之前是哪个公司面试的时候问到的,并不是一个常见的问题,我当时也没回答正确,就按照线程通信那一...
AI自动生成prompt媲美人类,网友:工程师刚被聘用,又要淘汰了
现阶段,得益于模型规模的扩大和基于注意力架构的出现,语言模型表现出了前所未有的通用性。这些大型...
20个JavaScript数组方法的实现
写在前面我想,大家一定对JavaScript中的数组很熟悉了,我们每天都会用到它的各种方法,比如push、pop、...
企业如何牢记云主权并确保云安全
事实表明,云主权必须是企业采用更广泛的云计算方法的核心。云计算一直是技术创新的最主要的推动者之...
一文带你了解TiDB
一、简介TiDB并不陌生,很多团队都在使用,我们为什么要是用它,它有哪些特点呢?TiDB是一款开源分布式...
如何在 VLC 播放器中裁剪视频
VLC媒体播放器是最好的媒体播放器之一。这款跨平台播放器功能丰富,可以播放任何可用的媒体格式。你会惊...