发布时间:2025 年 12 月 16 日
自适应网页设计是一种构建网站的方法,可确保网站在各种不同的浏览器、视口尺寸、设备和用户偏好设置下都能呈现出色的外观和功能。应用于排版时,主要考虑因素通常是根据浏览器宽度调整 font-size,这也会对 line-height 和 margin 等间距值产生影响。
作为设计师,我们有必要考虑浏览器中可用的空间,并相应地调整字体排版。另请务必注意,不同的用户在各种设备上会有不同的font-size需求,具体取决于您无法了解或控制的个人情况。因此,任何会剥夺用户对最终结果的控制权的操作都是危险的。用户在浏览网页时可以使用两种主要输入方式来影响字体大小:
- 在所有网站上提供默认的
font-size偏好设置。 - 按网站放大或缩小。
此演示的目标是使排版能够响应浏览器视口大小和用户输入。但请务必了解,排版对视口的响应程度越高,对用户偏好的响应程度就越低。如果您要实现自适应排版,请务必谨慎操作,并测试结果是否仍然可访问。
根据用户偏好协商基本 font-size
定义任何在线排版的第一步是根据用户的 font-size 偏好设置协商初始字号。此字体大小将用于网页上的大多数文字,并作为其他字体大小(例如标题)的基础。最简单的做法是使用 1em 为用户提供完全控制权,而无需进行任何调整。如果您未设置任何其他 font-size 值,1em 则表示用户偏好设置。另一方面,如果将 font-size 设置为像素或其他绝对单位(甚至视口相对单位),则会完全覆盖用户设置,应避免这样做。
不过,不同的使用情形需要不同的排版。对于文章,大号文字可能更易于阅读;而对于数据量大的网站,则可能需要采用更紧凑的设计,并使用较小的文字。无论哪种情况,您可能都需要建议一个适合设计的默认值,同时仍允许用户根据自己的独特情况调整结果。
方法 1:根据假设计算调节系数
一种常见的折衷方案是定义一个以 em 或 % 为单位的调整后 font-size,相对于用户默认 font-size。一般来说,此方法首先假设浏览器提供 16px 默认值,并且大多数用户会保留该默认值。如果您认为 20px 字号更适合您的网站,那么 font-size 为 1.25em 或 125% 通常会产生您想要的结果:
html {
/* 20px preferred, 16px expected: 20/16 = 1.25 */
font-size: 1.25em;
}
您也可以在此处使用 calc() 函数来显示数学公式,但您仍然需要知道公式是什么,即目标大小除以预期大小,再乘以 1em:
html {
font-size: calc(20 / 16 * 1em);
}
偏好值较大或较小的用户在一定程度上能够影响结果,因为您的默认值现在是相对于他们的偏好值而言的,在本例中是他们偏好值的 1.25 倍。但是,如果您和用户都请求 20px 默认值,而结果是 25px(即调整后的默认值再乘以 1.25),这可能会很奇怪,因为没有人要求这么大的尺寸。
方式二:让 clamp() 完成这项工作
一种更细致的方法是使用 CSS 比较函数,无需任何数学知识!与其假设 1em 等于 16px,并进行不可靠的从 px 到 em 的转换,不如将 1em 视为引用用户偏好的变量。无论 1em 代表什么像素值,max(1em, 20px) 的 font-size 始终会返回设计偏好设置 (20px) 和用户偏好设置 (1em) 中较大的那个值。这样一来,用户可以选择较大的字体大小,但不能选择较小的字体大小。
通过切换到 clamp() 函数,您可以允许用户在首选尺寸与您选择的默认尺寸相差过大时,在两个方向上进行缩放。例如,如果 clamp(1em, 20px, 1.25em) 的 font-size 为 20px,只要该值大于用户默认值,但不超过用户默认值的 125%,系统就会默认使用该值。
这样一来,当设计接近用户偏好设置时,设计会优先显示;但当用户偏好设置超出指定范围时,用户偏好设置仍会优先显示。无需进行任何转化计算,无需假设用户偏好的尺码,也无需将设计师值和用户值相乘。
通过将此值设置为 html 元素上的根 font-size,您现在可以在网站上的任何位置引用 1rem 作为协商的基本尺寸。
添加响应能力
为了使此 font-size 对视口做出响应,一种方法是添加媒体查询(或容器查询)断点。例如,您可以根据屏幕尺寸更改钳制值:
html {
font-size: clamp(1em, var(--base-font-size, 16px), 1.25em);
@media (width > 30em) { --base-font-size: 18px; }
@media (width > 45em) { --base-font-size: 20px; }
}
另一种方法是将视口或容器单位添加到静态基本值:
html {
font-size: clamp(1em, 16px + 0.25vw, 1.25em);
}
vw(视口宽度)或 vi(视口内嵌大小)单位表示浏览器(即呈现您网站的部分)总视口的 1%。同样,cqw 和 cqi 单位表示页面上内嵌大小容器的 1%。如需了解详情,请查看容器查询和单位演示。
这种方法通常称为流式排版,因为 font-size 的变化在一定范围的视口宽度内是恒定的,而不是在媒体或容器断点处从一个值跳到另一个值。不过,请不要被过渡的平滑度所迷惑,这种区别通常只有在测试中才能看到(如果您平滑地调整窗口大小)。用户很少(甚至从不)会看到这种效果。虽然用户可能会经常更改浏览器的大小或缩放级别,但他们必须以缓慢而流畅的方式进行这些调整,才能注意到断点和视口单位之间的区别。它只会影响过渡效果,而不会影响调整大小后的结果。
流体字体大小调整的主要优势在于,它无需手动计算或指定断点,可在任何给定尺寸下提供插值结果。您只需设置起点 (16px) 和变化率(每当视口增加 100px 时,0.25vw 将使 font-size 增加 0.25px),以及可能的最小值和最大值。当视口宽度为 1000px 时,font-size 将为 16px + 2.5px 或 18.5px,但此计算完全由浏览器处理。这是演示中采用的方法,使用 cqi 单位来展示基于容器的响应式设计。当在没有已定义容器的根 (html) 元素上使用时,cqi 单位仍是指视口大小。
如果您更喜欢以指定视口尺寸下的 font-size 为单位进行思考,不妨考虑使用更直接的媒体查询方法,这种方法更清晰明了。如果您尝试根据预期断点计算视口单位,情况会变得复杂。许多人通过从第三方工具中复制和粘贴值来完成此操作,但生成的代码更难理解或直接更改。一般来说,对于 CSS,最好的选择是能够最清楚地表达您的意图的选项。
警告:视口更改并不总是意味着相同的事情!
虽然媒体查询和 vi 单位的应用方式不同,但两种方法都基于相同的视口测量结果。如果视口的宽度为 600px,则 100vw 将等于 600px,并且将应用 (width > 500px) 媒体查询中的样式。
但“宽”视口是什么意思?600px实际上,像素并非在所有情况下都具有单一含义的固定大小。虽然像素宽度较小的视口自然会出现在较小的屏幕(例如手机)或较窄的浏览器窗口中,但这种假设并不可靠。事实上,放大和缩小浏览器窗口都会对测量的视口宽度产生相同的影响。一种操作(缩放)会改变像素的大小,而另一种操作(调整大小)会改变浏览器本身的大小,但这两种操作都会改变浏览器宽度上的像素数。通过视口测量,我们可以获得当前像素大小与当前浏览器窗口之间的关系。
对于用户而言,缩放和调整大小的用途截然不同。更改缩放级别的用户试图放大或缩小网页内容,而调整浏览器大小的用户只是在管理不同屏幕上的空间。即使用户意图不同,CSS 衡量结果也相同。随着窗口变小或像素变大,浏览器宽度上的像素会减少。
这种脱节使得自适应排版不可靠。如果您的文字设置为仅根据视口或容器调整大小,那么用户缩放将不会产生任何效果!
将视口相关单位的值更改为 1vw 或 100vw 会改变字号与视口之间的确切关系。1vw 字体的大小会随着视口大小每增加 100px 而增加 1px,而 100vw 字体的大小与视口大小完全相同。您可以更改该值,以使字体相对于浏览器更慢或更快地增大。但任何与视口相关的值都会在用户放大或缩小时保持不变,完全不受用户控件的影响。
同样,1vw 和 100vw 账号均不属于用户默认 font-size。
单独使用视口或容器相对单位设置 font-size 始终对用户不利。当 font-size 完全响应其容器时,它也无法响应用户默认设置或调整。即使出于好意并采取了保护措施,也应避免剥夺用户对数据的最终font-size控制权。这不仅会导致糟糕的用户体验,还可能违反法律通常要求的无障碍功能指南。具体而言,《无障碍网页内容指南》的第 1.4.4 部分要求“文本在不借助辅助技术的情况下可调整大小,最大可调整为原来的 200%”。
如何确保 font-size 值能够响应缩放操作
为确保相对于视口的 font-size 能响应缩放,必须将相对于视口的值作为对其他值的调整来应用。在 CSS 中,可以使用 calc() 函数或任何其他接受计算的数学函数(例如 min()、max() 和 clamp())来实现此目的。font-size 为 calc(16px + 1vw) 时,会同时考虑视口大小和像素的当前(缩放相关)大小。虽然 vw 单位不会受到缩放的影响,但基本值会受到影响。
这样一来,font-size 就会根据视口大小和用户的缩放设置进行调整。如果用户将缩放比例调整为 200%,则基值将以两倍大小 (32px) 呈现,而自适应值保持不变。1000px 视口最初会为您提供 16px + 10px = 26px 的 font-size,但在 200% 缩放比例下,字号只会增大到 42px,略高于 160%。这可能看起来不是一个极端的问题,但您的 font-size 越基于视口,缩放效果就越差。
在小屏幕上,font-size 主要来自基本像素值,并且对缩放的响应良好。但在大屏幕上,视口大小占渲染字体大小的比例更大,因此缩放效果较差。当 500% 缩放(大多数浏览器中的最大缩放比例)无法再提供 WCAG 1.4.4 所要求的 200% 字号增幅时,这种情况尤其危险。但即使在此之前,缩放功能失效也会令人沮丧。
0 到 2600px 宽。font-size 的纵轴也以像素为单位,显示 calc(17px + 2.5vw) 的结果。500% 缩放线使用相同的视口宽度横轴,但将纵轴视为百分比。
在图表的左边缘(0 视口宽度),500% 缩放完全有效。不过,随着浏览器尺寸的增加,这种效果会迅速下降,并且(不可缩放的)视口单位在 font-size 中所占的比例会越来越大。当浏览器宽度为 2040px 时,最大 500% 缩放只能使字号增加 200%。超过该点后,200% 的有效字体缩放将不再可行。
通过将此计算移至具有最小值和最大值的 clamp() 函数中,您可以强制执行边界,确保文本可缩放。根据 Maxwell Barvian 的说法:
如果最大字号小于或等于最小字号的 2.5 倍,则文字始终会通过 WCAG SC 1.4.4,至少在所有现代浏览器中是这样。
由于 @media 和 @container 查询与 vw 和 cqw 单位基于相同的衡量标准,因此使用断点更改字号时,也适用相同的逻辑。如果尺寸增加幅度过大,缩放功能将失效。您可以在以下可视化图表中实验这些值的互动方式:
如何确保 font-size 值能够响应用户默认设置
但 calc(16px + 1vw) 仍无法响应用户默认字体设置。为此,您可以使用 em 或 rem 单位(而非 px)设置基准值(或最小值和最大值)。综合来看,您会得到与关联演示相符的熟悉结果:
html {
font-size: clamp(1em, 17px + 0.24vw, 1.125em);
}
请注意:
- 最小值和最大值都使用
em单位,该单位基于用户偏好设置(并可响应缩放)。 - 额外的
vw值会保持在最低限度,以免对缩放造成过大影响。 - 最大尺寸 (
1.125em) 远小于最小尺寸 (1em) 的 2.5 倍,确保始终可以实现200%的有效font-size值。
包含 pow() 的字体排版比例
大多数设计都会使用多种字号!排版比例描述了多种字号之间的关系。这可以表示为基本尺寸和一系列用于计算其他尺寸的乘数。CSS 提供了一个相对于 medium 关键字的内置排版比例,该关键字是指用户的字体大小偏好设置或默认值 16px。完整的关键字规模如下:
xx-small:3/5 (0.6)x-small:3/4 (0.75)small:8/9 (0.89)medium:1(其他尺寸的倍数所依据的基本尺寸)large:6/5 (1.2)x-large:3/2 (1.5)xx-large:2/1 (2)xxx-large:3/1 (3)
此缩放比例是相对于用户默认值而非根 font-size,因此一旦您更改了网站的根 font-size,此缩放比例的效果就会变差。大多数作者最终都会使用自定义属性重新创建类似的类型比例,有时会使用相同的 T 恤尺码名称,有时则会选择一系列上下调整的数学比例。有许多第三方工具可用于根据常用比率生成这些音阶,这些比率大多借鉴自西方音阶:
html {
/* musical ratios */
--minor-second: calc(16/15);
--major-second: calc(9/8);
--minor-third: calc(6/5);
--major-third: calc(5/4);
--perfect-fourth: calc(4/3);
--augmented-fourth: sqrt(2);
--perfect-fifth: calc(3/2);
--major-sixth: calc(5/3);
/* the golden ratio*/
--golden-ratio: calc((1 + sqrt(5)) / 2);
}
不过,您无需借助外部工具即可在 CSS 中创建自己的比例,因为新的 pow() 函数可以为您生成比例,并以 1rem 作为您自己的基本尺寸!
html {
/* choose a ratio */
--scale: 1.2;
/* generate the scale using pow() */
--xx-small: calc(1rem * pow(var(--scale), -0.5));
--x-small: calc(1rem * pow(var(--scale), -0.25));
--small: calc(1rem * pow(var(--scale), -0.125));
--medium: 1rem;
--large: calc(1rem * pow(var(--scale), 1));
--x-large: calc(1rem * pow(var(--scale), 2));
--xx-large: calc(1rem * pow(var(--scale), 3));
--xxx-large: calc(1rem * pow(var(--scale), 4));
/* change the ratio for different viewport sizes */
@media (width > 50em) {
--scale: var(--perfect-fourth);
}
}
您不必使用整数步数来保持比例一致。事实上,常见的 12pt 字号比例每步大约使用 5 个分数。虽然此处的大尺寸使用整个步长进行缩放,但小尺寸使用分数进行缩放,因此缩放速度较慢。
借助 CSS mixin 和函数,您可以进一步精简该逻辑,而 progress() 等其他内置工具则可让您更轻松地创建从一个值流畅调整到另一个值的比例。不过,这些功能不在本演示的范围内。
根据网页内容器的大小进行响应
您可以使用 cqi 单位代替 vw 或 vi,使所有这些计算都能在容器查询中正常运行,但最好还是在 html 元素中保留用户的 font-size,这样每个排版容器都可以将该用户偏好设置作为 1rem 引用回来。在演示中,您会发现整个字体比例会应用于 body,而不是全局字体的根 html 元素,然后根据具有 type-set 属性的每个元素的容器大小进行重置。
这始终是与容器相对字体大小之间的权衡。您可以根据上下文为每个元素实现更流畅的字体大小调整,但代价是牺牲了整个网页的一致性。哪一个对您更重要取决于您的具体使用场景。请注意,自适应排版本身是一种权衡取舍,它会降低缩放等用户控件的有效性!
虽然自适应排版和排版比例是设计师的得力工具,但如果不需要,您无需让事情变得更复杂。用户默认和内置的类型比例也是不错的选择!不过,如果您确实选择了自适应(或流式)排版,请务必测试结果在不同用户默认设置和缩放设置下的表现。尽情享用吧!