IE用HTML5新要素のMinify生成

Updated / Published

latest logさんでエントリーされていたコードを削る方法がすごく勉強になったので、練習がてらに早速IE8以下でHTML5の新要素をCSSセレクタで使う際にdocument.createElement()で事前に書き出しておく必要があるコードをMinify化してみました。

書き出す必要のあるHTML5の新要素

まず最初に、IE8以下では未知の要素となるために書き出す必要のあるHTML5の新要素名を列挙しておきます。

  • article要素
  • aside要素
  • nav要素
  • section要素
  • hgroup要素
  • header要素
  • footer要素
  • figure要素
  • figcaption要素
  • time要素
  • mark要素

この他にも、HTML5の新要素にはcanvas要素, audio要素, embed要素, video要素, source要素, progress要素, meter要素, ruby要素, rt要素, rp要素, details要素, summary要素, datalist要素, keygen要素, output要素, command要素, menu要素(※menu要素はHTML2から規定されている要素名ですが全く異なる用途として新たに導入されています)があるのですが、この内、embed要素はIE3から、ruby要素,rt要素,rp要素はIE5のバージョンから既に先行実装済みであり、その他の要素についてはCSSで整形できるものでなっかり、全く機能すらしないのでdocument.createElement()で書き出す必要はありません。

Minify化のポイント

latest logさんからポイントを抜粋させてもらいます。

ドット演算子以降を自力で Minify する

JavaScriptは動的な言語なので、ドット演算子以降は基本的に minify しても圧縮されません。

document.createElement("div");
document.createElement("a");
document.createElement("p");

↓ このままだと、minify しても縮まらない

document.createElement("div");document.createElement("a");document.createElement("p")

ドット演算子によるアクセス( Object.property )は、Object["property"] のシンタックスシュガー(糖衣構文)です。

これらは、同じ処理速度でほぼ同じ価値を持ち、見た目がちょっと違うだけ(ドット演算子は制限も多いけど)。

そこで minifier が処理しやすいように、シンタックスシュガーを解除すると

var doc = document, createElement = "createElement";
doc[createElement]("div");
doc[createElement]("a");
doc[createElement]("p");

↓ minify

var a=document,b="createElement";a[b]("div");a[b]("a");a[b]("p")

すごいですよね、可読性は犠牲になりますが、同じ処理速度で且つここまで削ることができるというのは、目から鱗でした。

早速この書き方を取り入れて、HTML5の新要素を書き出してみます。

HTML5の新要素をIE8以下で認識させるためのコード例

代表的なライブラリにhtml5.jsがありますが、これと同様のことができる最小コードへの試みです。

var a=document,b="createElement",c="article,aside,nav,section,hgroup,header,footer,figure,figcaption,time,mark".split(','),i=c.length;while(--i>=0)a[b](c[i]);

よしなかなかシンプルにできたぞと思っていましたら、ppBlog officialさんでもまったく同じようにHTML5新要素のdocument.createElement()の最小書き出しがエントリーされていました。書き出している要素は便宜上異なっていますが、ppBlogさんで紹介されているコードの方がいろいろなアプローチで断然ショートでした。

どこで最初に見かけたのか失念しましたが、これを一行(ワンライナー)で簡潔に済ませたスクリプトを見たときはいたく感心しました。Dean Edwards氏のブログ もこうなっています。

"header,nav,article,section,aside,footer".replace(/\w+/g, function(a){document.createElement(a)});

上のポイントは、replaceメソッドの引数に関数を指定できて、その関数内では、正規表現にマッチした要素を適宜適用していく点です。ループみたいなことを勝手にやってくれる点ですね。おそらくこれ以上短くは書けないのではないかと思うのですが、息抜きに自分なりにいくつか考えてみました。

"header,nav,article,section,aside,footer".split(',').sort(function(a){return document.createElement(a)*1});

これも、似たような発想からですね。自動でなんかやってくれるという。

with("header,nav,article,section,aside,footer".split(',')))while(length)document.createElement(pop());

ここではwith構文を使ってみました。これもなかなかシンプルです。同じくwithと、Enumeratorを使って、

with(new Enumerator("header,nav,article,section,aside,footer".split(',')))for(;!atEnd();moveNext())document.createElement(item());

これは、ちょっと長いし、Enumerator Object はマイナーですかね。

短さ命で、グローバル変数の汚染なんて気にしないぜっ、という向きには以下のようなものもありかと思います。

s="header,nav,article,section,aside,footer".split(',');while(s[0])document.createElement(s.pop());

for文関連では、

for(i in s="header,nav,article,section,aside,footer".split(','))document.createElement(s[i]);

とか

for(i=0;n="header,nav,article,section,aside,footer".split(',')[i++];document.createElement(n));

とかですかねぇ。

コードを短くためのアプローチは本当勉強になります。なお、これらの書き方をしたからといってパフォーマンスがどの程度最適化されるのか等についてはわからないので、飽くまでもコード自体をMinify化するためのアプローチとして受け取ってください。