スキップしてメイン コンテンツに移動

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

main.js から CSS を読み込む」に、document.write() での CSS の読み込みについて追記。(2023/08/23)

<noscript>.textContent から CSS の URL を取得することが出来ないブラウザに AOSP 3未満を追加し、記事にも反映しました。(2023/01/05)

<noscript>.textContent から CSS の URL を取得することが出来ないブラウザを修正し、記事にも反映しました。Chrome 2~3 を除外していたのは誤りでした。(2022/05/01)

ブラウザ毎の CSS の分け方とファイル名の変更を反映。(2022/04/28)

<noscript>.textContent から CSS の URL を取得することが出来ないブラウザに Chrome 4~7 を加えました。(2022/03/18)

9~9.2x でも一部の非対応なモードのスタイルが適用」は誤りでした。(2022/03/01)

javascript を有効にするか Web ブラウザの変更を促す警告メッセージ」の HTML タグに </p> を追記。(2020/03/01)

javascript を有効にするか Web ブラウザの変更を促す警告メッセージ」の HTML タグを大幅に修正しました。github(2022/02/23)

<noscript>.textContent から CSS の URL を取得することが出来ないブラウザについて調査と実装を終えて、追記しました。(2022/02/09)

javascript を有効にするか Web ブラウザの変更を促す警告メッセージ」の HTML タグを追記しました。github(2022/02/03)

記事中でグレースフルデグラデーションとしている部分ですが、レグレッシブ・エンハンスメントと読み替えた方が良いかもしれません。(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 でも一部の非対応なモードのスタイルが適用されました。(この部分は誤りでした。2022/03/01)

中でも 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
IE10≦, Opera 9.5≦, Gecko 1.9.1≦, Safari 4.0.5≦, Chrome 8≦, AOSP 3≦, !IE && window.addEventListenermodern.css31
Gecko 1.5~1.9.0gck19.css
Mac IE5ie5mac.css
Safari ≦4.0.5, Chrome < 8, AOSP < 3, !IE && !Opera && !Gecko && !window.addEventListenermodern.css41
Opera 9.5 未満opr70.css, opr72.css, opr8.css, opr9.css
Gecko 1.5 未満gck07.css, gck08.css, gck09.css, gck12.css, gck13.css, gck19.css
IE4未対応

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

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

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

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

メッセージはテキストでは無く content で表示しています。これは CSS が無効の場合、IE5~9 以外のブラウザの全てでメッセージが表示されてしまうのを避ける為です。

<!--[if !IE]><!-->
<noscript>
<div id="-o-"><!-- 旧いブラウザには noscript p セレクタが効かない! -->
<style>/*<![CDATA[*/
/* common */
#-o- p{border:double 5px #f66;padding:1em;background:#300;color:#fff}

/* Opera 7.20~9.27 */
@media all and(-o-:0),not all and(-o-:0){
    html:first-child #-o-{display:block}
    :_{top:0} /* Opera ~7.11 skip next rule */
}
/* common */
#-o-{display:none}
#-o- p:after{content:attr(nojs) attr(opr)}

/* Opera 用ルールを先に、Gecko 用を後に書く */

/* Gecko ~1.8 */
@media \0 all{
    #-o-{display:block}
    #-o- p:after{content:attr(nojs) attr(gck)}
}
@-moz-document url-prefix(){
    /* Gecko 1.8~1.9.2 */
    _:not(),_:-moz-loading,#-o-{display:block}
    _:not(),_:-moz-loading,#-o- p:after{content:attr(nojs) attr(gck)}
    /* Gecko 1.9.1~1.9.2 */
    _:not(),_:-moz-handler-blocked,#-o-{display:none}
}
/*]]>*/</style>
<p nojs="Please enabled javascript or use new version of browser. At least " opr="Opera 9.5+." gck="Firefox 3.5+."><!-- inline 要素は不可 --></p>
</div>
</noscript>
<!--<![endif]-->

2022年2月23日に修正済。2022年3月1日に </p> を追記。<noscript> 下の p 要素の閉じタグを省略できない。

短縮版

<!--[if !IE]><!--><noscript><div id="-o-"><style>/*<![CDATA[*/#-o- p{border:double 5px #f66;padding:1em;background:#300;color:#fff}@media all and(-o-:0),not all and(-o-:0){html:first-child #-o-{display:block}:_{top:0}}#-o-{display:none}#-o- p:after{content:attr(nojs) attr(opr)}@media \0 all{#-o-{display:block}#-o- p:after{content:attr(nojs) attr(gck)}}@-moz-document url-prefix(){_:not(),_:-moz-loading,#-o-{display:block}_:not(),_:-moz-loading,#-o- p:after{content:attr(nojs) attr(gck)}_:not(),_:-moz-handler-blocked,#-o-{display:none}}/*]]>*/</style><p nojs="Please enabled javascript or use new version of browser. At least " opr="Opera 9.5+." gck="Firefox 3.5+."></p></div></noscript><!--<![endif]-->

2022年2月23日に修正済。2022年3月1日に </p> を追記。<noscript> 下の p 要素の閉じタグを省略できない。

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.5, Gecko < 1.5, Safari < 4.0.5, Chrome < 8, AOSP < 3, IE 以外の addEventListener をサポートしないブラウザは常にここで CSS を読み込みます。

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

<script>src からアセットディレクトリを取得します。Gecko < 1, Presto < 9 は、CSS 周りのバグを回避する為に document.write()<link> 要素を追加します。(そもそも Gecko 0.6~0.9.0は動的外部スタイルに非対応の為。Presto はスタイルの適用が document.write() でないと不安定だった為。2023/08/23 追記)

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

9 ≦ Presto < 9.5, 1 ≦ Gecko < 1.5, 3 ≦ Safari < 4.0.5, Chrome < 8, AOSP < 3 は <noscript>.textContent にアクセスして CSS のパスを取得することが出来なかった為、この経路になりました。(2022/02/09, 2022/03/18 追記, 2022/05/01 修正)