はじめに
CSSのbackdrop-filterやWebP画像のように、対応状況がブラウザやバージョンによってバラバラな機能を使うとき、みなさんはどうやって対応・非対応を判定していますか。User Agent文字列を見て分岐する方法は、UA偽装や新しいブラウザの登場、既存ブラウザの仕様変更であっという間に破綻してしまいます。
Modernizrは、こうした「このブラウザはこの機能に対応しているか」をUAではなく実際の機能テストで判定し、結果を<html>要素のCSSクラスとJavaScriptのグローバルオブジェクトの両方に反映してくれるライブラリです。プログレッシブエンハンスメント(対応ブラウザには豊かな体験を、非対応ブラウザには代替を提供する設計思想)を実践するうえで、長年デファクトスタンダードとして使われてきました。
Modernizrとは
Modernizrは、HTML5とCSS3の各種機能についてブラウザの対応状況を検出し、その結果を<html>要素のクラス名(例: .flexbox / .no-flexbox)と、JavaScriptのグローバルオブジェクトModernizrのプロパティ(例: Modernizr.flexbox)の両方で参照できるようにするJavaScriptライブラリです。2009年の登場以来、HTML5 Boilerplateの標準構成に組み込まれるなど、「対応していない機能をどう補うか」というプログレッシブエンハンスメントの実践を長らく支えてきました。
主な特徴
- CSS/JS両対応の検出結果 -
<html>要素のクラス名でCSSの出し分けが、ModernizrオブジェクトのプロパティでJSの分岐ができる - カスタムビルドによる軽量化 - 250種類以上あるfeature-detectsから、実際に使う項目だけを選んでバンドルできる
- 非同期テストにも対応 - Flashサポートの有無のように同期的に判定できない項目は、
Modernizr.on()でコールバック形式の結果を受け取れる - 独自テストの追加 -
Modernizr.addTest()で自前の検出ロジックをライブラリに組み込める - 豊富な実績 - GitHub上で2.5万を超えるスターを持ち、長年にわたりプロダクションで使われ続けている
インストール
npm経由でインストールできます。ビルド用のCLI(modernizrコマンド)が同梱されています。
npm install --save-dev modernizr
公式サイト(modernizr.com)のビルダー画面からブラウザ上で必要な検出項目を選び、生成済みのJSファイルをそのままダウンロードする方法もあります。npm経由でのビルド設定が面倒な場合は、こちらのほうが手軽です。
基本的な使い方
Modernizrは、素のまま<script>で読み込んで使うライブラリではなく、「必要な検出項目だけを選んでビルドする」設計になっています。まず設定ファイルで検出したい機能を指定します。
// modernizr-config.json
{
"minify": true,
"options": ["setClasses"],
"feature-detects": [
"css/flexbox",
"css/backdropfilter",
"img/webp"
]
}
optionsにsetClassesを指定すると、判定結果を<html>要素のクラス名として自動付与する機能がビルドに含まれます。この設定を元に、CLIでカスタムビルドを生成します。
npx modernizr -c modernizr-config.json -d modernizr-custom.js
生成されたmodernizr-custom.jsは、判定対象のCSS/JSより先に評価される必要があるため、<head>内で読み込みます。
<head>
<script src="modernizr-custom.js"></script>
</head>
setClassesを有効にすると、対応状況に応じて<html>要素にflexbox/no-flexboxのようなクラスが自動的に付与されます。CSS側ではこのクラスを起点に、対応・非対応それぞれのスタイルを書き分けられます。
.no-flexbox .layout {
display: table;
}
.flexbox .layout {
display: flex;
}
JavaScript側では、グローバルのModernizrオブジェクトから同じ判定結果を参照できます。
if (Modernizr.webp) {
document.body.classList.add('use-webp');
} else {
document.body.classList.add('use-jpg-fallback');
}
実践的なユースケース
画像フォーマットのフォールバック
WebPやAVIFのような新しいフォーマットは軽量ですが、古い環境では表示できません。Modernizr.webpの判定結果を使えば、UAで振り分けるよりも確実にフォールバックできます。
// data-webp属性に本来のWebP画像パスを仕込んでおく
document.querySelectorAll('img[data-webp]').forEach((img) => {
if (Modernizr.webp) {
img.src = img.dataset.webp;
}
// Modernizr.webpがfalseならsrc属性のJPEG/PNGがそのまま使われる
});
非同期テストで対応状況を判定する
Flashサポートの有無のように、その場で同期的に判定できない項目はModernizr.on()でコールバック形式で受け取ります。ビルド設定のfeature-detectsに対象のテストを含めておけば、判定が完了した時点でコールバックが呼ばれます。
Modernizr.on('flash', (result) => {
if (!result) {
// Flash非対応環境向けの代替コンテンツに差し替える
document.querySelector('.flash-embed').replaceWith(fallbackElement);
}
});
独自の検出項目を追加する
標準のfeature-detectsに無い判定が必要な場合、Modernizr.addTest()で自作のテスト関数を登録できます。登録したテストは、標準の検出項目と同じように<html>要素のクラスとModernizrオブジェクトの両方に反映されます。プロパティ名は常に小文字に変換される点に注意してください。
Modernizr.addTest('hasjquery', function () {
return 'jQuery' in window;
});
if (Modernizr.hasjquery) {
// jQueryが読み込まれている前提の初期化処理
jQuery('.legacy-widget').widgetInit();
}
まとめ
Modernizrは、UA判定という不安定な手法に頼らず、実際の機能テストに基づいてブラウザの対応状況を判定できるライブラリです。CSSクラスとJavaScriptオブジェクトの両方に結果を反映してくれるため、CSS設計とJSのロジックを同じ判定基準で書き分けられるのが強みです。ブラウザの標準対応が進んだ今でも、backdrop-filterや画像フォーマットのような「まだ対応がバラつく機能」を扱う場面では、UA判定よりも確実な選択肢として検討する価値があります。まずは自分のプロジェクトで使っている機能を1つ、feature-detectsに加えるところから試してみてください。