近來在調整間距時,常見使用 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的尺寸 - 電腦上為
--spacing-lg-max的尺寸 - 其間為可變且平滑伸縮
,是非常好用的模式吧。
無障礙設計上的陷阱是什麼?
問題在於要符合WCAG 2.0 成功準則 1.4.4「調整文字大小」時。
此準則原本是在智慧型手機普及之前制定的,其目的是「在電腦上即使放大至 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 踏入網頁世界,不知不覺間,標記、前端、專案指導與無障礙,樣樣精通的「技藝仙人」。自 Liberogic 創業初期就跨領域活躍,如今是公司內部的活字典般的存在。最近沉迷於運用提示詞提升效率的探索,想著「無障礙相關的工作,能不能更依賴 AI 呢?」技術與思考,仍在持續進化中
二俣 步
IAAP認證網頁無障礙專員(WAS) / 標記工程師 / 前端工程師 / 網站總監