CSS2KB をちょっと改良 + CSSファイル に Canvas の描画ルーチンを埋め込む

CSSにデータを埋め込む方法を考えてみた(CSS2KB) - latest log の続き

CSS2KB とは CSS にちょっとした情報を埋め込むトリックの1つ。 list-style: url(1dot.gif?key=val) から key=val を取り出せるというもの。

CSS2KB の難点は、ダミーファイル(1dot.gif) が実際に必要だった点

  • ダミーファイルのロード ⇒ 通信が余計に発生するよね
  • ダミーファイルが 404 だと? ⇒ key=val が取り出せない ⇒ それってまずいよね

ダミーファイルが邪魔なので、もうちょっと考えてみた

試しに、URL を list-style: url(?key=val) だけにしてみたら

  • ダミーファイル(1dot.gif)が不要に
  • CSS のファイルパスが補完された形で取得できる ⇒ 補完された CSS のURLがついでに取れてくる
    • この URL は何か使い道がありそうな、そんな雰囲気。

ということに(いまさら)気づいた。

サンプル

.hoge { list-style: url(?key=val) }

から key=val を取り出すには、こういったコードを用意して…

// uu.hash.css2kb - hash from CSS implemented data
var _ie = !!document.uniqueID;
var doc = document;
function uuhashcss2kb(name) { // @param String/Array: className or [className, ...]
                              // @return Hash: { key: val, ... }
  function _qsparse(m, key, value, s) {
    s = decodeURIComponent(value);
    return rv[decodeURIComponent(key)] = isNaN(s) ? s : parseFloat(s);
  }
  function _trimurl(str) {
    return (!str.indexOf("url(") && str.indexOf(")") === str.length - 1)
           ? str.slice(4, -1).replace(/^\s*["']?|["']?\s*$/g, "") : str;
  }
  var rv = {}, cs, url, v, i = 0,
      ary = (typeof name === "string") ? [name] : name,
      div = doc.body.appendChild(doc.createElement("div"));

  while ( (v = ary[i++]) ) {
    div.className = v;
    cs = _ie ? div.currentStyle : window.getComputedStyle(div, null);
    url = _trimurl(cs.listStyleImage);
    if (url && url.indexOf("?") > 0) {
      url.slice(url.indexOf("?") + 1).replace(/(?:([^\=]+)\=([^\;]+);?)/g, _qsparse);
    }
  }
  doc.body.removeChild(div);
  return rv;
}

こうすれば CSS に埋め込んだ Hash を取得できる。
uu.hash.css2kb("hoge") -> { key: val }

doc.body.appendChild(div) して doc.body.removeChild(div) してるのは、IE でノードツリーに参加していない要素の currentStyle が null になるから。IE 以外なら appendChilde とかは不要。

IE6+, Safari3x+, Google Chrome, Opera9.5+ で動く

その気になれば、

CSSファイルに 文書構造(HTML)を埋め込むことも、生の画像データを埋め込むことも、はたまた js そのものを埋め込むことも自由さ。

お勧めは、HTML5::Canvas の描画ルーチンをCSSに埋め込むこと
ctx.beginPath();
ctx.fillRect(0,0,100,100);
ctx.closePath();

を encodeURIComponent 等で処理して、CSS に埋め込み

.CloseButton_css2kb {
  list-style: url(?js=ctx.beginPath%28%29%3Bctx.fillRect%280%2C0%2C100%2C100%29%3Bctx.closePath%28%29%3B)
}

これで描画できる。

function drawCloseButton(ctx) {
  var js = uu.hash.css2kb("CloseButton_css2kb").js;
  eval(js);
}


ちょっとしたパラダイムシフトだ。