在调整间距时,近来常见的做法是使用 clamp() 设置最小值到最大值之间的可变数值。
这种方法对响应式适配非常方便,但若考虑到 无障碍的放大显示(缩放),则存在一个容易忽略的陷阱。
常见的 clamp() 写法示例
例如,在使用 clamp() 调整间距时,通常会这样编写。
:root {
--clamp-base: 16;
--clamp-viewport-min: 375;
--clamp-viewport-max: 1440;
--spacing-lg-min: 24;
--spacing-lg-max: 48;
--spacing-lg-slope: calc(
(var(--spacing-lg-max) - var(--spacing-lg-min)) / (var(--clamp-viewport-max) - var(--clamp-viewport-min))
);
--spacing-lg-intersection: calc(
(var(--spacing-lg-max) - var(--clamp-viewport-max) * var(--spacing-lg-slope)) / var(--clamp-base)
);
--spacing-lg: clamp(
calc(var(--spacing-lg-min) / var(--clamp-base) * 1rem),
calc(var(--spacing-lg-intersection) * 1rem + 100 * var(--spacing-lg-slope) * 1vw),
calc(var(--spacing-lg-max) / var(--clamp-base) * 1rem)
);
}
具体说明从略,
- 在智能手机上为
--spacing-lg-min的尺寸 - 在 PC 上为
--spacing-lg-max的尺寸 - 在此期间可灵活且平滑地伸缩
,这是一种非常实用的模式,对吧?
无障碍设计中的陷阱是什么?
问题出在尝试符合 WCAG 2.0 成功标准 1.4.4「调整文本大小」 的时候。
该标准最初制定于智能手机普及之前,其意图是“即使在 PC 上放大至 200% 也能正常浏览”,但同样的条件也适用于智能手机浏览器。
实际在智能手机上放大至 200% 时,常常会出现以下现象。
- 由于文本放大(缩放)的作用,基于
rem单位设置的 页面边距也会一同放大。 - 结果,包围原本内容的 边距变得过宽。
- 最终,内容显示区域被极度压缩,导致布局错乱、内容难以阅读。
注:不过从现实情况来看,在要求遵守 WCAG 的海外政府网站等场景中,也很少见到相应的处理。推测原因可能是成本效益不高,而且在智能手机上放大至 200% 的需求本身也几乎不存在,因此在实际开发现场,往往被认为“即使不做,也不会造成大问题”。
如何解决这个问题?
重要的是,不要使用会受文字放大影响的 rem,而应使用 vw 等基于视口的单位,并且即使放大页面,也不要让留白过度增大。
但如果只使用 vw 来指定,就无法发挥 clamp() “可以控制最小值和最大值”的优势。
这时就要用到 min() 函数!
min() 会在传入的值中采用“最小的值”。利用这一特性,可以在正常状态与放大状态下切换所应用的值。
写法如下。
--spacing-lg: min(
calc(var(--spacing-lg-min) / var(--clamp-viewport-min) * 100vw),
clamp(
calc(var(--spacing-lg-min) / var(--clamp-base) * 1rem),
calc(var(--spacing-lg-intersection) * 1rem + 100 * var(--spacing-lg-slope) * 1vw),
calc(var(--spacing-lg-max) / var(--clamp-base) * 1rem)
)
);
在 375 CSS px 下显示时,min 的第一个值是 --spacing-lg-min 的值 24px 换算为 vw 后的 6.4vw。
clamp() 的最小值为 1.5rem = 24px,但在 200% 放大时会变为 48px,因此左侧的 6.4vw 更小,将会应用该值。
也就是说,
- 正常状态(100% 显示):
clamp()的值会比基于vw的值更小。min()会采用较小的值,因此clamp()生效,显示会随屏幕宽度变化。
- 放大时(200%显示):
- 随着放大,
clamp()中的rem值会变大,而基于vw的值则会变小。 - 应用基于
vw的值后,留白会按屏幕宽度的比例固定,因此可以防止过度放大。
- 随着放大,
这样一来,就能够兼顾“响应式的便利性”与“对无障碍的考虑”!
※ 顺带一提,在PC显示中,连同留白一起放大通常能更好地保持设计的平衡,因此仅在智能手机上以--clamp-viewport-min为基准应用。
对比实际效果
上方为仅使用 clamp,下方为 min+clamp。
在智能手机上放大到200%,差异会非常明显。
※ iOS Safari 可通过地址栏左侧的图标进行放大,Android Chrome 可通过右上角的图标进行放大。
总结
- clamp() 非常适合用于响应式的间距调整
- 但在放大显示时,间距也会随之放大,可能导致版面错乱
- 通过与 min() 结合使用,可以实现平衡的方案:常规情况下保持可变,放大时加以控制
如果您在意 WCAG 合规,采用这类实现方式会让您更加安心。虽然“在智能手机上考虑到 200% 放大”的实现目前还比较少见,但在不影响日常浏览舒适度的前提下,也能有效降低无障碍方面的风险。
此外,如果希望对间距以外的细节进行调整,也可以通过指定较窄断点的媒体查询来实现。
@media (max-width: 239px) {
/* 拡大時に適用したいCSS */
}
例如,当宽度为 375px 的屏幕放大到 200% 时,浏览器会将视口宽度按“一半的尺寸(约 188px)”进行计算。因此,可以利用这一较窄的条件来进行匹配。
※ 239px 只是一个示例值。建议在考虑未来屏幕尺寸扩大的同时,调整至不影响常规显示的数值。
将“clamp() + min()”与“较窄断点的媒体查询”结合使用,就能实现更加灵活、更加可靠的无障碍方案!
从 DTP 进入 Web 领域,不知不觉间,标记、前端、项目指导、无障碍样样精通的“技术仙人”。自 Liberogic 创业初期起就身兼多职,如今已是公司内的活字典般的存在。最近沉迷于用提示词提升效率的探索:“无障碍支持,能不能更多地依靠 AI 呢?”技术与思考仍在不断进化中。
二俣 歩
IAAP认证网页无障碍专家(WAS) / 标记工程师 / 前端工程师 / 网页总监