素人がプログラミングを勉強していたブログ

プログラミング、セキュリティ、英語、Webなどのブログ since 2008

連絡先: twitter: @javascripter にどうぞ。

CSSを追加する関数

の39番目とGM_addStyleの実装と最適化 - 0xFFについて。
まず、style要素を使う方法。

function addStyle(css) {
  var style = document.getElementsByTagName('style').item(0);
  if (!style) {
    style = document.createElement('style');
    style.type = 'text/css';
    (document.getElementsByTagName('head').item(0) || document.documentElement).appendChild(style);
  }
  style.appendChild(document.createTextNode(css + '\n'));
}

元からあるstyle要素を利用する方法。コメント欄参照。うまくいく。これはうまくいかない。HTMLのページだと、style要素の中身が<!-- body { color: blue; } -->のようにコメントで括られた物になっている事があって、(style.firstChild instanceof Commentではない)ので、普通にtextNodeを追加すると、<!-- body { color: blue; } --> body { background-color: red; }のようになって正しく解釈されない。当然、createCommentで生成したCommentノードを追加しても無視される。
そして、createTextNodeだと元からあるCSSが再パーズされるんじゃないかと思ってこの方法は使ってない。
次に、link要素を作る方法。

function addStyle(css) {
  var stylesheet, link;
  if (!addStyle.__link) {
    stylesheet = document.createElement('link');
    stylesheet.rel = 'stylesheet';
    stylesheet.type = 'text/css';
    addStyle.__link = stylesheet;
  }
  link = addStyle.__link.cloneNode(true);
  link.href = 'data:text/css,' + encodeURI(css);
  (document.getElementsByTagName('head').item(0) || document.documentElement).appendChild(link);
}

や、closureを使って

var addStyle = function () {
  var stylesheet = null;
  return function (css) {
    var link;
    if (!link) {
      stylesheet = document.createElement('link');
      stylesheet.rel = 'stylesheet';
      stylesheet.type = 'text/css';
    }
    link = stylesheet.cloneNode(true);
    link.href = 'data:text/css,' + encodeURI(css);
    (document.getElementsByTagName('head').item(0) || document.documentElement).appendChild(link);
  }
}();

とする方法。この方法は、関数を呼ぶ度にlink要素が毎回作られる。deadspaceで使っている物と似ているが、btoaを使っていないので、a:visited::before { content: "既読"; }のような日本語が入っているCSSでもエラーにならない。dataスキームにしたいだけならbase64を使う必要はない。
他にはdocument.createCDATASectionを使ったりdocument.styleSheets.item(0).insertRuleなどが考えられるが、前者はHTMLでは使えないしXMLの場合でもCSSに]]>という文字が入れられない。後者は複数のスタイルを同時に追加できないので要件を満たしていない。
結論は、link要素を追加するのがいいと思う。