linkタグとstyleタグの差が非常に謎い

JavaScriptCSSを使ってる時に気になったことなんですが、
styleタグでスタイルを定義すると問題ないんですが、linkタグでcssをリンクするとJavaScript側からスタイルルールにアクセスする際に詰まるという話。

現象

  • Chrome(v12のみ確認)で発生し、FirefoxOpera,Safariでは発生しない。
    • IEはそもそもcssRulesが存在しないので論外。
  • styleタグで指定したStyleにはwindow.styleSheets[*].cssRulesが存在
  • \の様にリンクしたCSSにはwindow.styleSheets[*].cssRulesが存在しない

確認出来るコード

  • とりあえず次のコードを試すと確認出来る。
  • test.css
.testclass {
	background 	: blue;
	width		: 100px;
	height		: 100px;
}
  • test.html(動く版)
<html>
    <head>
        <style type="text/css">
            @import "test.css";
        </style>
        <script>
            onload = function() {
                css_list = document.styleSheets;
                css_list.item(0).insertRule(".testclass{ background:yellow;}",css_list.item(0).cssRules.length)
            }
        </script>
    </head>
    <body>
        <div class="testclass">
    </body>
</html>
  • test.html(動かない版)
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="test.css">
        <script>
            onload = function() {
                css_list = document.styleSheets;
                css_list.item(0).insertRule(".testclass{ background:yellow;}",css_list.item(0).cssRules.length)
            }
        </script>
    </head>
    <body>
        <div class="testclass">
    </body>
</html>
  • 確認
    • (動く版)と(動かない版)の違いはtest.cssのインポート方法。前者は@importルールで、後者はlinkタグ。
    • (動く版)を動かす
    • (動かない版)を動かす
      • Opera,firefox,Safariではもんだいなく動く。
      • Chromeは「Uncaught TypeError: Cannot read property 'length' of null」が発生
    • どちらもOpera / Firefoxでは動く。

まとめ

  • ひとまず、styleSheets.cssRulesを触るような操作をする場合はstyleタグ内に@importルールを用いてリンクした方が良さそう。
  • ただしあんまり綺麗じゃない。
  • また、この対策を取った場合でもcssRulesは「CSSImportRule型」であることに注意。「CSSStyleRule型」は取れないので、styleプロパティは取得できない。
  • これってWebkitの実装のバグじゃないの? (でもドキュメントには別扱いとも同等扱いとも書かれていないのである意味バグじゃないかもしれない)

後日談

  • プロジェクト見にに行ったら、既に問題として報告されていた。
  • Chromeのバグらしい。 -> Issue49001
  • ただ、かなり前に報告されているのに直されていないので「バグ」というか「仕様」男かもしれない。詳細はIssue参照で。