Thinking in the Grey

フォントサイズを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 でフォールバックする

フォントサイズをrem指定しつつ画面幅で縮尺する

Related Articles