フォントサイズをrem指定しつつ画面幅で縮尺する
問題点
- そもそも画面幅に合わせてフォントサイズを縮尺する方法はアクセシビリティ上の問題から非推奨
font-sizeをvwで指定すると、ブラウザで画面を拡大しても文字が拡大しない- WCAG の達成基準 1.4.4「テキストのサイズ変更」に抵触する
- W3C は、ビューポート単位で文字サイズを指定する方法を失敗例 F94 として挙げている
Understanding SC 1.4.4 Resize Text
F94: Failure of Success Criterion 1.4.4 due to incorrect use of viewport units to resize text
使い所
- フォントサイズが
vwで指定されている既存サイトを改修するとき - 画面幅に合わせて縮尺するレイアウトにロックインされていとき
remを基準にすることで、少なくともブラウザの文字サイズ設定は効くようにできる- ただしページのズームは CSS 上の画面幅を縮めるため、係数が下がって拡大が打ち消される
実装方法
スケール係数を CSS カスタムプロパティ --fontScale に切り出し、calc(1rem * var(--fontScale)) の形で使う
CSS
@propertyで--100vwを<length>として登録するtan(atan2())でvwを px 相当の数値に変換し、割り算できるようにする- 対応ブラウザでは JS なしでスケールが成立する
@property --100vw {
syntax: "<length>";
initial-value: 0;
inherits: false;
}
:root {
--100vw: 100vw;
/* vw → px 相当の数値へ変換 */
--window-width: tan(atan2(var(--100vw), 1px));
/* PC: 768〜1200 → 最大1 */
--fontScale: min(calc(var(--window-width) / 1200), 1);
}
@media (max-width: 767px) {
:root {
/* SP: 390px 基準 */
--fontScale: calc(var(--window-width) / 390);
}
}
body {
font-size: calc(1rem * var(--fontScale));
}
JS + CSS
@property、tan()、atan2()に対応していない環境や、古めの Safari 向けのフォールバック- 画面幅を検知して係数を計算する
resizeで画面幅に変更があったら、CSS 変数--fontScaleを更新する- CSS 側の値が正しく計算できていない場合だけ JS を有効にする
- 計算式と 767px のブレークポイントは CSS と揃える
(() => {
const root = document.documentElement;
const updateFontScale = () => {
const w = window.innerWidth;
let fontScale;
if (w <= 767) {
// SP: 390px 基準
fontScale = w / 390;
} else {
// PC: 1200px 基準(最大1)
fontScale = Math.min(w / 1200, 1);
}
root.style.setProperty("--fontScale", String(fontScale));
};
const cssValue = getComputedStyle(root)
.getPropertyValue("--fontScale")
.trim();
// CSS が正しく計算できていない場合のみ JS を有効化
if (!cssValue || cssValue === "0" || cssValue === "NaN") {
updateFontScale();
window.addEventListener("resize", updateFontScale);
}
})();
まとめ
- 画面幅でフォントサイズを縮尺する方法は、アクセシビリティ上は基本的に非推奨
- やむを得ない場合は
calc(1rem * var(--fontScale))の形にして、ブラウザの文字サイズ設定を活かす - 計算は CSS の
@propertyとtan(atan2())を優先し、未対応環境だけ JS でフォールバックする