GM_addStyleの実装と最適化
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がいくつも出来てるのが好きじゃない。って、個人的な好みでした。反省。