エメラルドマウンテンの麓。

対応ブラウザをかなり拡げた場合の最適なCSSの読み込み方法、web-doc-baseのブートシーケンスについて

記事中でグレースフルデグラデーションとしている部分ですが、レグレッシブ・エンハンスメントと読み替えた方が良いかもしれません。(2021/12/16)

CSS を一本化しているにも係わらず CSS の読み込み経路が複数になり、やや複雑になってきたので記事化しておくこととしました。

  1. はじめに
    1. プログレッシブエンハンストを一部で諦めた件について
  2. CSS読み込みのチェックポイント
    1. ファーストビューのインライン化
    2. document.write('<link>') について
    3. なるべく外部 javascript からメインの CSS を読み込まない
  3. ブラウザ毎の経路の解説
    1. 条件付きコメント非対応ブラウザで javascript が無効の場合
    2. IE5~9 の場合
    3. インライン javascript から CSS を読み込む
    4. main.js から CSS を読み込む

1. はじめに

僕の Web 文書用ベースプロジェクト web-doc-base では、新旧を問わず広範なブラウザで閲覧性を良好にすべく開発を続けています。

この内、プログレッシブエンハンストを諦めざるを得ない一部のレガシーブラウザに対しては、各ブラウザ用の CSS を用意して Javascript で読み込むようになりました。javascript が無効の場合は、モダンブラウザ用の CSS が読み込まれてしまうことになります。つまり、グレースフルデグラデーションでの対応です。

併せてモダンブラウザについても Javascript が有効な場合は、Javascript で CSS を読み込むこととなりました。これは、レガシーブラウザが無用なモダンブラウザ用の CSS をロードしない為に、<style><noscript> で囲んだことによる変更です。

1. 1. プログレッシブエンハンストを一部で諦めた件について

長らく javascript の無効なレガシーブラウザについてもある程度の閲覧性を確保したい、と考えてきましたが、Opera 9.5 未満の @media クエリがヤバすぎるので諦めました。以下の記述は 8.5x 以下についてですが、9~9.2x でも一部の非対応なモードのスタイルが適用されました。

中でも Opera 8 以下には @media 規則に致命的な不備がありました。ダークモードやハイコントラストモード用のスタイルが問答無用に適用されていく様を見て、Javascript に依存しない CSS ハックでの対処を放棄せざるを得ませんでした。

2. CSS読み込みのチェックポイント

  1. ファーストビューのインライン化
  2. document.write('<link>') について
  3. なるべく外部 javascript からメインの CSS を読み込まない

2. 1. ファーストビューのインライン化

ここ何年かで Web 文書のパフォーマンスチェックツールが推奨してくる、ファーストビュー部分の CSS のインライン化は未着手です。

2. 2. document.write('<link>') について

モダンブラウザでは document.write() での <link rel="stylesheet"> の追加はページのパフォーマンスの観点から推奨されません。この件については web.dev による解説文の該当箇所を次に引用します。

一方で一部のレガシーブラウザでは document.write('<link>') でないとスタイルの適用が不安定なものがあります。僕が確認しているのは、Opera 9.0 未満と Gecko 1.0 未満です。

Using document.write() can delay the display of page content by tens of seconds and is particularly problematic for users on slow connections. Chrome therefore blocks the execution of document.write() in many cases, meaning you can't rely on it.


document.write() を使用すると、ページコンテンツの表示が数十秒遅れることがあり、低速回線のユーザーにとっては特に問題となります。そのため、Chrome は多くの場合、document.write() の実行をブロックしており、document.write() に依存できないようになっています。

2. 3. なるべく外部 javascript からメインの CSS を読み込まない

クロスブラウザ DOM 操作ライブラリ等の組み込まれた、main.js から <link rel="stylesheet"> を追加していたところ、一度だけですが、この main.js がネットワーク側の理由で読み込まれないケースに遭遇しました。つまり CSS も読み込まれません。

このレアケースに対処する為に、殆んどのブラウザについてはインラインの javascript で <link> を追加することにしました。ライブラリのサポートが必要等の一部のブラウザでのみ、main.js から <link> 要素を追加しています。

3. ブラウザ毎の CSS を読み込む経路の解説

HTML ファイルから CSS ファイルを読み込むフロー図。draw.io で閲覧、編集する

ブラウザ毎に異なる CSS を読み込む経路について解説します。フロー図の1~4の各経路番号について詳しく記述していきます。

  1. 条件付きコメント非対応ブラウザで javascript が無効の場合
  2. IE5~9 の場合
  3. インライン javascript から CSS を読み込む
  4. main.js から CSS を読み込む
ブラウザ毎の CSS ファイルと経路番号
cssjs enabledjs disabled
IE 5, 5.5, 6, 7, 8, 9ie5win.css, ie55.css, ie6.css, ie7.css, ie8.css, ie9.css22
モダンブラウザ(Opera 9.5≦ || Gecko 1.9.1≦ || Safari 3≦ || !IE && window.addEventListener)modern.css31
Opera 9~9.2xopr9.css
Gecko 1~1.9.0gck121.css, gck190.css
Mac IE5ie5mac.css41
Safari ≦3 || !IE && !Opera && !Gecko && !window.addEventListenermodern.css
Opera 9 未満opr70.css, opr72.css, opr8.css
Gecko 1 未満gck097.css
IE4未対応

3. 1. 条件付きコメント非対応ブラウザで javascript が無効の場合

IE 以外のブラウザ用または Mac IE5 用の CSS が読み込まれます。

このケースでは Gecko 1.9.1 未満、Opera 9.5 未満にも modern.css が読み込まれてしまいます。デザインが崩れるに留まらず、最悪の場合ではブラウザがクラッシュします。

次の HTML タグで「javascript を有効にするか Web ブラウザの変更を促す警告メッセージ」を表示して閲覧者に対処を促します。幸いにクラッシュしなかった場合は、閲覧者側の対処を期待できます。

準備中

3. 2. IE5~9 の場合

Javascript の死活にかかわらず、条件付きコメントで各ブラウザ用の CSS を読み込みます。

3. 3. インライン javascript から CSS を読み込む

殆んどの IE 以外のブラウザ(addEventListener をサポートするもの)と Mac IE 5 用の CSS を読み込ます。

main.js のロードに失敗するケースに備えて、ごく一部のブラウザを除いてインライン javascript で CSS を読み込みます。

load または DOMContentLoaded イベントコールバック内で <link> 要素を追加します。CSS のパスは <noscript>textContent から求めます。

3.4. main.js から CSS を読み込む

Presto < 9, Gecko < 1, Safari < 3, IE 以外の addEventListener をサポートしないブラウザは常にここで CSS を読み込みます。

インライン javascript の CSS ローダーを使わないビルド設定の場合、全ての IE 以外のブラウザと Mac IE 5 もここから CSS を読み込みます。

<script>src からアセットディレクトリを取得します。Presto < 9, Gecko < 1 は、CSS 周りのバグを回避する為に document.write()<link> 要素を追加します。

Safari < 3 には load イベントがいない為、このフォールバックのある main.js から CSS を読み込みます。