零弐壱蜂

[CSS] ブラウザのデフォルトフォントサイズを取得する方法

背景

ブラウザにはユーザーが設定できるデフォルトのフォントサイズがある。多くのブラウザでは初期値が16pxだが、ユーザーがアクセシビリティ等の理由で変更している場合がある。例えばChromiumでは設定画面から「極大」を選択すると24pxになる。

課題

単純なアプローチとしてdocument.documentElementfontSizeを取得する方法が考えられる。

const htmlFontSize = getComputedStyle(document.documentElement).fontSize;
console.log(htmlFontSize); // "16px"

しかし、CSSリセットやフレームワークがhtml要素にfont-sizeを設定している場合、この値はブラウザのデフォルトではなくCSSで上書きされた値になる。

/* よくあるCSSリセットの例 */
html {
  font-size: 62.5%; /* 10px相当にする手法 */
}
// CSSリセットが適用されている場合
const htmlFontSize = getComputedStyle(document.documentElement).fontSize;
console.log(htmlFontSize); // "10px" ブラウザのデフォルトではない

解決方法

CSSのfont-size: mediumキーワードを利用する。

CSSの<absolute-size>キーワードmediumは、ユーザーが設定したブラウザの標準フォントサイズに対応する。mediumという値はユーザー設定を基準とするが、font-size宣言そのものは通常どおりカスケードに従う。

要素にfont-size: mediumを指定し、その計算値をJavaScriptで読み取る。

const measureElement = document.querySelector('.measure-element');
const defaultFontSize = parseFloat(getComputedStyle(measureElement).fontSize);
console.log(defaultFontSize); // 16(デフォルト設定の場合)
.measure-element {
  font-size: medium;
}

デモ

一時要素を使った実装

DOMに計測用の要素を常駐させたくない場合、一時的な要素を生成して計測後に削除する。

function getBrowserDefaultFontSize() {
  const el = document.createElement('div');
  el.style.fontSize = 'medium';
  document.body.appendChild(el);
  const size = parseFloat(getComputedStyle(el).fontSize);
  el.remove();
  return size;
}

console.log(getBrowserDefaultFontSize()); // 16

document.bodyが未生成のタイミングでは失敗するため、DOMContentLoaded後に実行する。

視覚的な影響を避ける実装

visibility: hiddenposition: absoluteを併用すれば、一時要素によるレイアウトシフトを回避できる。

function getBrowserDefaultFontSize() {
  const el = document.createElement('div');
  el.style.cssText = 'font-size:medium;visibility:hidden;position:absolute';
  document.body.appendChild(el);
  const size = parseFloat(getComputedStyle(el).fontSize);
  el.remove();
  return size;
}

remとの関係

CSSのrem単位はhtml要素のfont-sizeを基準とする。CSSリセットでhtmlfont-sizeが変更されている環境では、1remの実際のピクセル値とブラウザのデフォルトフォントサイズが一致しない。

html {
  font-size: 62.5%; /* 1rem = 10px にする手法 */
}
// この環境では
const remSize = parseFloat(getComputedStyle(document.documentElement).fontSize);
console.log(remSize); // 10 — 1remの値

const defaultSize = getBrowserDefaultFontSize();
console.log(defaultSize); // 16 — ブラウザのデフォルト

参考