こんにちは,太田です。前々回,前回とJavaScriptの基礎的な部分を解説しました。今回はJavaScriptからみたHTMLを中心に,DOMについても少しずつ解説しています。
JavaScriptとHTML
FirefoxのアドオンやサーバーサイドJavaScriptなどの例外をのぞいて,多くのJavaScriptはHTML上で実行されるので,HTMLは土台となる重要な要素です。そこでHTMLの基礎的な部分からHTMLとJavaScriptの関係を解説します。
DOCTYPEとレンダリングモード
HTMLといえば最初に書くのはDOCTYPEです。現在使われているDOCTYPEはHTML4.01,XHTML1.0,XHTML1.1といくつかの種類があり,さらにその中でTransitionalやStrictなどの違いや,XHTMLではXML宣言の有無(本来は必須ですが)などバリエーションがあります。DOCTYPEがなかったり,間違ったフォーマットで記述されている場合など,レンダリングエンジンが後方互換モードになります。後方互換モードには色々と問題があるため,標準準拠モードにするために正しいDOCTYPEを記述するように気をつけるとよいでしょう(DOCTYPEについては,DOCTYPE スイッチについてのまとめと一覧表に詳しいまとめがあります)。
特に理由がなければ,HTML5のDOCTYPEを使うのがよいでしょう。HTML5はまだ仕様の策定途中ですが,HTML5で定義されているDOCTYPEは互換性の問題を考慮されているのでIE 6などのブラウザでも標準モードとして認識されますし,従来のDOCTYPEよりも大幅にシンプルになっています。例えば,HTML4.01 Transitionalに従ったHTMLは以下のようになります。
HTML4.01のDOCTYPEとサンプルHTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<link rel="stylesheet" type="text/css" href="a.css">
<title>HTML4.01 サンプル</title>
</head>
<body>
<h1>sample html 4.01</h1>
</body>
</html>
これをHTML5のDOCTYPEなどを使って書き直すと次のようになります。
HTML5のDOCTYPEとサンプルHTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="a.css">
<style>
body{
margin:3px;
}
</style>
<title>HTML5 サンプル</title>
</head>
<body>
<h1>sample HTML5</h1>
<script>
alert(document.doctype);
</script>
</body>
</html>
DOCTYPEのほか,charsetの指定,style, script要素のtype属性の省略(デフォルトがCSS, JavaScriptなので,それらを省略できる)など,かなり簡略化しています。これらは互換性の問題がなく,記述量を減らすことができるので積極的に使うことができます。
script要素
script要素といえば,内部に直接JavaScriptを書くときにはコメント(<!-- -->)で囲むものだと思われている方が多いかもしれません。入門書などでは「script要素に対応していないブラウザのためにコードがそのまま表示されないようにコメントで囲む」と説明されていることが多いようです。しかし,実際にscript要素に対応していないブラウザはNetscape Navigator 1くらいのものです。古い携帯電話に搭載されているブラウザもscript要素に対応していないことがあるようですが,その場合script要素に関係なくまともに表示できないので,必要なら携帯専用ページを用意するべきでしょう。
なお,外部のJavaScriptファイルを読み込む場合はなるべくcharsetで文字コードを指定しておくとよいでしょう。JavaScriptファイルに日本語のコメントを入れてなかったり,HTMLの文字コードと揃えてある場合は省略しても問題ありませんが,いずれにしても書いておいて損はありません。また,レスポンスヘッダのContentTypeで文字コードを記述するという方法もあります。
また,必要に応じてnoscriptでJavaScriptを無効にしている場合にも配慮しておくとよいでしょう。最近ではJavaScriptに対応していないのではなく,ユーザーがJavaScriptをあえて無効にしているケースが増えています。JavaScriptを有効にすることでどういった機能が使えるのか説明しておけば,ユーザーは必要に応じてJavaScriptを有効にするでしょう。
HTMLの解釈とJavaScriptの実行
ウェブブラウザはHTMLの解析中にscript要素を見つけたらその場でそのJavaScriptを(外部スクリプトの場合は読み込み後に)実行します。その間はそれ以降のHTMLの解析が止まり,ユーザーの操作も受け付けない状態になります。そのため,script要素を記述する位置,その内容には十分に配慮する必要があります。
特に,HTMLの解析を止めて実行されるので,そのscript要素以降にあるHTMLはまだ読み込まれていないためJavaScriptからアクセスできないという問題があります。それを回避する一般的な方法がonloadイベントです。しかし,onloadは画像の読み込みを含む完了なので,完了まで時間がかかってしまうことも珍しくありません。そこでよく使われる方法がscript要素をHTMLの最後(bodyタグを閉じる直前)に記述する方法と,DOMContentLoadedというHTMLの解釈が終わったタイミングで実行させる方法です。
script要素を最後に記述する方法は簡単でわかりやすく,どのブラウザでも動作するので,HTMLを編集できるケースならこの方法がおすすめです。DOMContentLoadedはIEへの対応が少々手間ですがHTML側を編集しなくてもよいというメリットがあります。Firefoxや,Safari 3.1以降,Opera 9,ChromeなどはDOMContentLoadedをサポートしているので次のように記述できます。
DOMContentLoadedの利用例
document.addEventListener("DOMContentLoaded", function(){
// HTMLの読み込み後に実行されるので,要素を参照できる
var element = document.getElementById(ID);
}, false);
IEでも動作する読み込み待ち関数は次のとおりです。なお,(サポートするか微妙なラインではありますが)Safari 3.0.4などもDOMContentLoadedをサポートしていないので注意が必要です。
DOMContentLoadedの実装例
function dom_ready(callback){
var isLoaded = false;
if (document.addEventListener){
document.addEventListener("DOMContentLoaded",function(){
callback();
isLoaded = true;
}, false);
// addEventListenerをサポートしているが,DOMContentLoadedを
// サポートしていないブラウザ用にloadイベントもセットしておく
window.addEventListener("load", function(){
if (!isLoaded) callback();
}, false);
} else if (window.attachEvent) { // for IE
if (window.ActiveXObject && window === window.top) {
_ie();
} else {
window.attachEvent("onload", callback);
}
} else {
var _onload = window.onload;
window.onload = function(){
if (typeof _onload === 'function') {
_onload();
}
callback();
}
}
function _ie(){
try {
document.documentElement.doScroll("left");
} catch( error ) {
setTimeout(_ie, 0);
return;
}
callback();
}
}
IEの場合,読み込み中にdoScrollというメソッドを呼び出すとエラーになる特徴を利用して,エラーが発生しなくなったら読み込みが完了したと判断するようになっています。なお,IE 9はaddEventListener,DOMContentLoadedをサポートする予定です。
dom_ready関数の利用例
dom_ready(function(){
// HTMLの読み込み後に実行されるので,要素を参照できる
var element = document.getElementById(ID);
});

