HTML5タグのtagNameが小文字になる

uuAltCSS.js は uuQuery.js にセレクタの処理を委譲しています。

<style>
article>div:nth-child(even)>section {
  -uu-background-image: url(../../img/cover01.jpg);
}
</style>

        <article class="round">
          article
          <div class="view">
            <section class="round">section</section>
          </div>
          <div class="view">
            <section class="round">section</section>
          </div>
          <div class="view">
            <section class="round">section</section>
          </div>
        </article>

上記のマークアップだと、本来は真ん中の(2段目の) section要素の背景に画像が設定されるはずなのですが、IEOperaでは画像が設定されません(ヒットしない)。

調べてみたところ、section 要素の tagName, nodeName が "SECTION" ではなく "section" になっています。
HTML4DOM の仕様では tagName は大文字になるはずなので、それを期待している以下のコードで問題が起きています。

uuQuery.js のコード片

function addTag(tag, contentType) {
  var lo = tag.toLowerCase(),
      up = tag.toUpperCase();
  if (!(lo in _htmlTag)) {
    _xmlTag[up] = _htmlTag[lo] = _htmlTag[up] = up;
    _xmlTag[lo] = lo;
  }
  return contentType === 1 ? up : tag;
}

function querySelectorAll(expr, context) {
 ... 略 ...

    // "E > F"  "E + F"  "E ~ F"  "E"  "E F" phase
    if ( (match = CHILD.exec(expr)) ) {
      tag = match[2];
      tag = tag ? (_tags[tag] || addTag(tag, _contentType)) : "*";
      isUniversal = tag === "*"; // true: tag is universal selector

      if (match[1]) {
        joint = JOINT1[match[1]];

        if (joint === 1) { // 1: "E > F"
          for (; i < iz; ++i) {
            for (v = ctx[i].firstChild; v; v = v.nextSibling) {
              if (v.nodeType === 1) {
                if (isUniversal || v.tagName === tag) { // ここでヒットしない
                  r[++ri] = v;
                }
              }
            }
          }
  ... 略 ...
}

仕方ないので、addTag 関数に、IE または Opera で、HTMLモード(contentType=1)で、HTML5TAGS にヒットする場合は小文字の要素名を返すように改造して対応しました。

var HTML5TAGS = "abbr,article,aside,audio,bb,canvas,datagrid," +
                "datalist,details,dialog,eventsource,figure," +
                "footer,header,hgroup,mark,menu,meter,nav," +
                "output,progress,section,time,video,";

function addTag(tag, contentType) {
  var lo = tag.toLowerCase(),
      up = tag.toUpperCase();
  if (!(lo in _htmlTag)) {
    _xmlTag[up] = _htmlTag[lo] = _htmlTag[up] = up;
    _xmlTag[lo] = lo;
  }

  if (_ie || _mm.opera) {
    if (contentType === 1) {
      if (HTML5TAGS.indexOf(tag + ",") >= 0) {
        return lo;
      }
    }
  }
  return contentType === 1 ? up : tag;
}

おまけ

数ヶ月ぶりのセレクタねたなので、もうちょっと書くよ。

  • jQuery1.3(Sizzle) は大丈夫? とソースを見てみたら、 element.nodeName === tag.toUpperaCase() のように必ず大文字化してから比較してるようなので、未知のタグが増えても問題は発生しないようです。
    • ただ…必ず大文字化するようだと XML 文書に非対応かつ W3Cのテストケースでもエラーになります。jQuery は HTML文書専用ね。
  • jQueryより速い」と一部サイトでソースコードも精査せずに、鳴り物入り(?)で紹介されてた Peppy.js ですが、去年の10月を最後に更新されてないようです。
    • 「コードに仕込まれたインチキを全て取っ払ったら、すげぇ遅くなるはずだ」と思ってたので、ある意味予想通り