17 May 2011

DOM の textContent と innerText について

一つ前のエントリで JavaScript のトピックスについて紹介しました.

避けなければいけない JavaScript の失敗 - Please Sleep

この中でエレメントノードのテキスト部分を取り出す innerText プロパティについて説明していましたが, これは非標準で Firefox ではサポートされていません. 標準になっているものとして textContent というプロパティがあります.

一応エントリ下部のコメント欄紹介ページでこのことについて触れているんですが, もっときちんと取り上げないとフェアじゃない気がしたので, 改めてこの2つのプロパティについて取り急ぎエントリにしました.

仕様とブラウザサポート

textContent も innerText もある要素の text 部分にアクセスするためのプロパティです. 例えばこのような html に

<div id="myDiv">
     This text is in Div.
     <p>A para in div element.</p>
</div>

こういうふうに js からアクセスすると

document.getElementById('myDiv').innerText;
// または
document.getElementById('myDiv').textContent;

このような文字列が返されます.

This text is in DIV. A para in div element.

Chrome で実行してみた例:

textContent は W3C で標準化されたプロパティです. IE 以外のブラウザがサポートしています.

innerText は IE4 から実装されている IE の独自機能です. Firefox 以外のすべてのブラウザがサポートしています. IE 独自のものなので明文化された仕様はありません.

サイ本6版では次のような, ちょっとクロスブラウザな textContent 関数が紹介されていました. ノードの text が空文字列だった場合, “” は JavaScript では falsy なので, “===” で比較しているのがポイントですね.

/**
 * With one argument, return the textContent or innerText of the element.
 * With two arguments, set the textContent or innerText of element to value.
 */
function textContent(element, value) {
    var content = element.textContent; // Check if textContent is defined
    if (value === undefined) { // No value passed, so return current text
        if (content !== undefined) return content;
        else return element.innerText;
    }
    else { // A value was passed, so set text
        if (content !== undefined) element.textContent = value;
        else element.innerText = value;
    }
}

両者の違い

両者はだいたい同じような挙動をしますが, いくつかの点では異なっています.

  • textContent は script タグの中を返しますが, innerText は返しません
  • textContent は空白類の文字 (スペース・タブ・改行など) を html に書いてあるまま返します. innerText はある程度見やすいように変換します

innerText の挙動の違い

上で述べたように, textContent と innerText の挙動が異なるため, 得られる text も違うものになります. 問題は innerText の挙動もブラウザによって微妙に異なる点です. こちらのブログでは WebKit と IE の innerText で得られるテキストの違いについて触れられています.

Plain Text vs innerText vs textContent by Mike Wilcox » Club✩AJAX

またこちらの stackoverflow の回答では, safari 2.x 系での innerText の実装が buggy であると言われています.

javascript - ‘innerText’ works in IE, but not in Firefox - Stack Overflow

問題への対策

先ほどのブログではブラウザ間の挙動を吸収するような “getPlainText()” という関数が紹介されていました.

http://clubajax.org/files/lang/plain-text.js

ただ, 個人的には上の StackOverflow での kangax さんの意見に共感しました.

  • innerText や textContent の挙動の差異を吸収するのは大変
  • なので, まず要件をもう一度みなおして本当に textContent / innerText が必要か考える. 大抵の場合は innerHTML からタグを取り除くだけで十分.
  • 無理ならば DOM Tree を走査して Text ノードを見ていく

余談: インラインの script タグ

ちょっと話はそれますが, script タグのちょっと面白い利用法について.

サイ本6版のコラムにもあったのですが, script タグに src 属性を指定せずタグ中に文字列を書くと, ブラウザ上には表示されない文字列になります. 中の文字列は text というプロパティで取得できます. また script 要素の type 属性に “text/javascript” 以外の値を指定すれば JavaScript の処理系もこれを無視してくれます. これを利用すると JavaScript から自由に扱える文字列を script タグの中に書いておくことができます.

現実の利用例としては, John Resig さんがブログで紹介していた小さな関数ICanHaz といった js 製のテンプレートエンジンは script タグ (type は text/html) の中にテンプレートを記述するというアプローチをとっています.

参考

初めてのJavaScript 第3版 ―ES2015以降の最新ウェブ開発
Ethan Brown
オライリージャパン
売り上げランキング: 17,881