これからのDOM API 第1回 そもそもDOMとは何か

ライブラリやフレームワークを使い慣れると、最近のDOM仕様について、つい疎くなることも。このシリーズでは、比較的新しいDOM APIをおさらいします。まずは入門編としてDOMについての基本を押さえます。

発行

著者 矢倉 眞隆 フロントエンド・エンジニア
これからのDOM API シリーズの記事一覧

はじめに

JavaScriptフレームワークを使いコンポーネントを作る手法が広まり、jQueryなどを使ってWebページのDOMを直接操作するものは少なくなっているように感じます。標準で定義されているDOM APIなんて、なおさらです。

とはいえ、ちょっとしたことをしたい場合に便利なメソッドや、これまで不便だった挙動が改善されるなど、DOM自体も少しずつ進歩しています。レガシーなプロジェクトをメンテナンスしたり、パフォーマンスを追求したいというシーンでは、標準のDOM APIの知識が役に立つことも多いでしょう。

このシリーズではそれら標準のDOM APIをいくつか紹介していきます。数は多くありませんが、普段JavaScriptをそこまで書かない方が、キャッチアップするために使っていただければと思います。

が、その前に今一度、「DOM」っていったい何なのかを確認してみましょう。

DOMはブラウザがWebページを解釈したもの

DOMは「Document Object Model」という単語の略で、「ドム」などと呼ばれます。「『ドキュメント』に関する『オブジェクト』の『モデル』」なのですが、それぞれを説明したところでピンとこないので、実際に見てみましょう。

この記事を開いている状態で、開発者ツールのElementsパネルを開いてみましょう。HTMLファイルのソースコードのようなものが見えますが、これがDOMツリーと呼ばれる、DOMの表現です。

ただのHTMLファイルに見えるが、これはDOMをHTMLのソースコードっぽく表現したもの。

「ソースコードのようなもの」と言いましたが、ここで見えているものはHTMLファイルのソースコードではありません。これは、記事を表示するまでに解釈したHTML、CSS、JavaScriptによって構築された、記事の「DOM」をソースコードのようにわかりやすく表示したものです。

DOMには、HTMLのさまざまなものが「オブジェクト」として存在しています。要素、属性、テキストなどが、それぞれ要素オブジェクト、属性オブジェクト、テキストオブジェクトとして存在しています。

個々がどのようなオブジェクトになっているかは、コンソールから調べられます。Elementsパネル上で何か要素を選択してください。選択したら、コンソールに移り、console.dir($0)と入力します。すると、現在選択されている要素のオブジェクトがどのようなプロパティを持っているかが調べられます。

console.dir()はオブジェクトのプロパティを見るときに使うコンソールのAPI。$0は直前に選択された要素やJavaScriptオブジェクトを指すコンソール専用プロパティ。

オブジェクトにはさまざまなプロパティがあり、いくつかのプロパティは別のオブジェクトを参照しています。こうしたオブジェクトの内容や、オブジェクト同士のつながりを表現したものがDOMで、そのつながりをツリー状に表現されたものをDOMツリーと呼んでいます。表現方法は、ほかにも考えられるのでしょうが、ツリーとしての表現が一般的なので、「DOMツリー」が単に「DOM」と略して呼ばれています。

DOMにアクセスするためにDOM APIがある

ブラウザはWebページ上の何かを動的に変更する際に、ソースコードを書き換えるわけではありません。JavaScriptからDOMにアクセスし、その内容やプロパティを変更しているわけです。

そうしたオブジェクトへのアクセス(「li要素だけを集めたい」とか)や、オブジェクトの操作(新しい要素を追加したい)をする仕組み(API)として、DOM APIがあります。先ほどconsole.dir()見た要素オブジェクトにはaccessKeychildrenclassListなどさまざまなプロパティが見えましたが、これらもDOM APIのひとつです。

次回以降は、このDOM APIの一部について、この数年に新しく追加されたものを紹介します。

DOMの仕様にはいろいろある

HTMLやCSSと同じように、DOMにも標準仕様があります。基本となる仕様はWHATWGで策定されている「DOM Standard」(以下「DOM仕様」)で、過去にW3Cで策定されたいくつかのDOM関連仕様を包括し、更新しています。

DOM仕様では、HTMLやXML文書に共通して利用可能な、要素や属性などのオブジェクトが定義されています。また、何かが起こったことを示すイベントの仕組みなど、JavaScriptをWebで使うには欠かせない機能も含まれています。

ただ、DOM仕様書だけを見ればDOMのすべてがわかるかというと、そうではありません。

DOM仕様で定義されているオブジェクトやプロパティ、メソッドは、HTMLやXML、SVGなど、幅広いマークアップ言語上で、汎用的に使えるAPIを定義しただけです。たとえば、要素を表すElementや、要素やテキストなどを追加する際に使うappendChild()メソッドは、マークアップ言語を問わず使えるでしょう。

一方、特定のHTML要素にだけ存在するような属性・状態にアクセスするインターフェースは、当然定義されていません。

たとえば、img要素。要素ですからElementオブジェクトとしていいかもしれません。しかし、src属性はすべての要素に存在するわけではありません。また、「画像が読み込まれた」という状態もすべての要素に共通するわけではありません。要素は要素でも「HTMLの要素」さらには「HTMLのimg要素」と、細かくカスタマイズされていないと表現できないものがあったり、それらを扱うには不便だったりします。

ですので、汎用的なElementが継承され「HTMLの要素」を表すHTMLElementや、さらにそれを継承し「HTMLのimg要素」を表すHTMLImageElementなどが存在します。これらカスタマイズされたオブジェクトを汎用的なDOM仕様書で定義するのはうまくありませんから、HTML仕様書で定義されています。こちらのほうが自然ですよね。

というわけで、DOM仕様書にはすべてのDOM APIは定義されていません。必要に応じて、HTML仕様書やSVG仕様書も見なければいけません。

また、仕様の編纂の都合から、DOM仕様書やHTML仕様書には取り込まれていない機能もあります。さらには、HTML仕様書へ取り込まれたり、HTML仕様で定義された一部機能がDOM仕様書に移管されたりなど、機能も流動的だったりします。

次回以降紹介するAPIは、DOM仕様に追加された新しいAPIや既存機能の拡張が主ですが、一部DOM仕様書外のものも取り上げます。仕様書がどれかを覚えておくのは面倒ですし、筆者も「あれ、これ移動したんだ」とたまに気づいたりするので、ドキュメンテーションも一緒に紹介しようと思います。

【コラム】DOMの基盤を固めたHTML5

DOMもHTMLと同じように、最初からかっちりとした仕様があったわけではありません。当時のブラウザ(Netscape NavigatorやInternet Explorer)が実装していた、HTMLやブラウザをJavaScriptから操作するAPIのうち、技術や環境にあまり依存しない基本的なオブジェクト(要素、属性、テキストなど)、HTML関連(HTMLの要素型や属性)、イベントモデルといったものについては、DOM仕様として標準化が試みられ、今日のDOM仕様にも一部が受け継がれています。

標準化されたものもありますが、標準化されないものもありました。標準がなければ、それらをどう実装するかはアプリケーション次第です。結果として、サポート状況が違ったり、細かい挙動が違うといった「Web開発あるある」な状態がDOMにもありました。

たとえば、HTML5以前には、HTMLファイルをどうパースし、どのようなDOMツリーを構築するかといった仕様がありませんでした。根幹中の根幹なのに、それを記すことなく、雰囲気にまかせていたというのは、なかなかにびっくりです。そして、そんな状況でも発展していた。当時のWeb開発者やライブラリ製作者の苦労が忍ばれます。

この解決に動いたのが、何を隠そうHTML5です。HTML5は新しい要素やたくさんのアプリケーション向けAPIを導入しましたが、それらを不自由なく使えるようにすべく、挙動の差異を埋めるという目標も掲げてはじまったものです。詳細が何も定義されていなかった過去のHTML仕様やDOM仕様と比べ、規模が膨大に、そして仕様がブラウザ実装仕様書のようになったのには、こういう理由があります。

DOM APIも少しずつ進歩している

HTML5仕様と並行して、DOM仕様も更新されはじめ、新しい機能が追加されているのをご存知でしょうか。

追加されている機能は、jQueryなどのライブラリにある便利なAPIからの影響を受けており、見通しの悪かったコードをわかりやすくできます。

また、標準ではなくブラウザが独自に実装していた機能も、既存のWebサイトとの互換性やその便利さを理由に、一部標準化、実装が行われています。

次回以降は、新しいAPIや、挙動が拡張され便利になったものを取り上げます。