読者です 読者をやめる 読者になる 読者になる

GM_addStyleの実装と最適化

JavaScript

GreasemonkeyのGM_addStyle関数は呼び出すたびにhead内にstyle要素を作る。
Greasemonkey 0.8.20080609.0のソースより。

function GM_addStyle(doc, css) {
  var head, style;
  head = doc.getElementsByTagName("head")[0];
  if (!head) { return; }
  style = doc.createElement("style");
  style.type = "text/css";
  style.innerHTML = css;
  head.appendChild(style);
}

これは、はっきり言って効率が悪い
補足:CSSをミスったときの影響が自分だけに留まるというメリットはある。
補足2:効率悪いと書いたけど、体感できるような話ではないと思うので、効率悪いは言い過ぎでした。ごめんなさい。*1

に対して、Greasemetal の gm_utils.user.js(Greasemetalのインストールディレクトリのuserjsフォルダ内にある) では最初に作ったstyle要素を使いまわすように書かれている。

    var style;

    function GM_addStyle(css) {
        if (!style) {
            var head = doc.querySelector('head');
            if (!head) {
                return;
            }
            style = doc.createElement('style');
            style.type = 'text/css';
            head.appendChild(style);
        }
        style.appendChild(doc.createTextNode(css));
    }

The functions were written by my colleague Amachang.

http://labs.cybozu.co.jp/blog/kazuhoatwork/2008/09/greasemetal_version_02_release.php

とあるのでid:amachangが書いたものらしい。


で、(oAutoPagerizeでは)1回目でstyleを作成して、同時に関数自体を書き換えるようにした。

function addCSS (css){
	var style = document.createElementNS(HTML_NAMESPACE, 'style');
	style.id = 'autopagerize_style';
	style.type = 'text/css';
	var root = document.getElementsByTagName('head')[0] || document.body;
	root.appendChild(style);
	addCSS = function(_css){
		style.appendChild(document.createTextNode(_css+'\n'));
	};
	addCSS(css);
}

この方法だと if(!style)も省略できる。ただ読み難い。

無名関数でも同じようなことは出来る。

var addCSS = (function(){
	var style = document.createElement('style');
	style.type = 'text/css';
	var root = document.getElementsByTagName('head')[0] || document.body;
	root.appendChild(style);
	return function(css){
		style.appendChild(document.createTextNode(css+'\n'));
	};
})();

この場合、関数を使う使わないに関わらずstyle要素を作ってしまう。

割と一長一短あるけど、結局のところid:amachangのGM_addStyleが一番スマートでした。


あ、ただ、amachangのGM_addStyleはdoc.createTextNode(css+'\n')にしておいたほうが良さそう。CSSが壊れてたとき、どこが問題かわかりにくくなるので。

*1:インスペクトしたときとかに誰が作ったのかわからないstyleがいくつも出来てるのが好きじゃない。って、個人的な好みでした。反省。