Michael Wallent
Microsoft Corporation
April 3, 2000
日本語版最終更新日 2000 年 11 月 21 日
この記事は、もともと MSDN Online Voices のコラム "DHTML Dude" に掲載されたものです。
Microsoft 社内には、DHTML の使い方に関する質問をするための電子メールのエイリアスが用意されています。今月のコラムとサンプルでは、配置と編集に関するいくつかの質問に焦点を当てることにします。
CSS Positioning
CSS Positioning が登場したのは 1997 年のことですが、いまでもこれに関する質問が寄せられます。一番多いのは、「オブジェクトの実際の位置はどうすればわかるのか」という質問です。この質問に対する答えはそれほど簡単ではありません。配置されているかどうかを問わず、任意の要素の位置を取得するための確実な方法は、element.offsetLeft/offsetTop プロパティを調べるというもので、要素の offsetParent を基準とした位置が得られます (offsetParent は、要素の座標空間を与える親です)。しかし、配置されたオブジェクトと配置されていないオブジェクトを入れ子にするようになると、事態は興味深くなります。offsetParent が移動しても、その子の offsetLeft/offsetTop 値から得られる値は変わりません。つまり、offsetParent はそのすべての子に対して、配置に関するカプセル化の機能を提供しているといえるのです。
この配置のサンプルを見てみてください。全体像を見るためには、ウィンドウを最大化する必要があります。
マウスを移動すると、ステータス バーに大量の情報が表示されます。
-
Mouse Wnd
: マウスの、ウィンドウを基準とした位置
-
Mouse Prnt
: マウスの、ローカル コンテナを基準とした位置
-
Scroll
: ウィンドウがどれだけスクロールされたか (スクロールされている場合)
-
Over
: マウスの下の要素のタグ名と ID
-
Offset Prnt: マウスの下の要素の offsetParent (存在する場合)
-
Prnt Pos
: マウスの下の要素の offsetLeft/offsetTop 位置。ローカル座標
-
Window Pos: 要素の、ウィンドウ座標での位置
マウスを下の方の要素の上に置くと (Middle という名前の青い長方形)、offsetParent は DIV Outer になります。ID が Outer の DIV は相対配置に設定されているので、独自の座標空間を作成します。実際、相対的または絶対的に配置されているすべての要素は、独自の座標空間を作成します。
その後、マウスを緑色の長方形 Inner の上に移動すると、別の効果が生じます。Inner DIV の親は Middle です。しかし、Middle は配置されていないので、座標空間を作成しません。この場合、offsetParent は、チェーンの中の独自の座標空間を作成している最初の親である Outer DIV となります。
さて、offsetParent に関する情報とオブジェクトの位置が得られたので、オブジェクトのウィンドウを基準とした位置を計算する 1 つの方法としては、offsetParent チェーンをたどり、すべての offsetLeft/offsetTop 値を足し合わせていくというものが考えられます。この方式は実現可能ですし、信頼できる結果が得られます。しかし、階層が深くなると、処理に時間がかかります。
offsetParent のチェーンをたどる代わりに、別の位置決定方式を使用することができます。上の例では、マウス移動イベントが発生するたびに、3 つのタイプの座標情報が得られていました。スクリーンを基準としたマウス位置、ウィンドウを基準とした位置、そしてローカル座標です。ここから、ローカル座標をウィンドウ座標に変換するための相対デルタを計算することができます。
次にそのためのコードを示します。
we = window.event.srcElement;
if ((we.offsetParent) && (we.offsetParent.tagName != "BODY")) {
windowDX = window.event.clientX - window.event.x;
windowDY = window.event.clientY - window.event.y;
} else {
windowDX = 0;
windowDY = 0;
}
posX = we.offsetLeft + windowDX + document.body.scrollLeft;
posY = we.offsetTop + windowDY + document.body.scrollTop;
この計算を正しく行うためには、マウスの下にある要素が <BODY> 要素以外の offsetParent を持っている場合にのみ、ウィンドウ オフセット値を足し合わせるようにする必要があります。<BODY> 要素に直接に含まれている要素については、オフセットを計算する必要はありません。また、スクローリングも考慮に入れる必要があります。ウィンドウがスクロールされると、この計算値は無効になります。ウィンドウのスクロール量に応じて、scrollLeft/Top 値を加えなくてはなりません。
自動配置
配置のサンプルには、「自動配置」と呼ばれる機能も含まれています。
絶対配置されている要素は、フロー スペースを占有しません。通常、これは要素の左上隅の位置を指定しなくてはならないということを意味します。しかし、左上隅の位置を指定しないと、要素はその通常の計算されたフロー位置に配置され、フロー スペースは占有しません。これは、少しばかり細かい制御で "float" スタイルの効果を作り出せる便利な手段です。上のサンプルの最初の例では、Blue <DIV> が絶対配置されており、左上隅の指定は行われていません。そのすぐ後の Green <DIV> が正確な位置に配置されており、Blue と Green の <DIV> が重なり合っていることに注目してください。
自動配置は流し込みモデルと絶対配置モデルの間のギャップを埋めます。自動配置を使うと、フローとレイアウトを制御しながら、ブラウザに要素の位置を決定させることができます。
編集
このクールな編集機能のサンプルでは、ドロップダウン ボックスの中で書式設定ツールを使用しています。この サンプル では、テキストの書式を変更することができます。テキストを選択すると、その書式値がコンボ ボックスに反映されます。
次に該当箇所のコードを示します。
otherDoc.body.onselect = showSelectionFont;
function showSelectionFont() {
var f;
f = otherDoc.queryCommandValue("FontName");
if (!f)
f = "null";
f = f.toLowerCase();
c = FontSelection.all[f];
if ((c) && (!c.selected)) {
c.selected = true;
}
}
"otherDoc" プロパティは、編集モードになっている IFrame の中の文書へのポインタです。文書内の選択範囲が変更されるたびに showSelectionFont() メソッドが呼び出されるように、onselect イベントをフックしています。このメソッドは queryCommandValue() メソッドを使って、FontName プロパティを決定します。これは、現在選択されているテキストの FontName プロパティを返します。テキストが選択されていなければ、既定値が返されます。
フォント名を入手したら、選択範囲の中のオプション リストで名前を検索するのは時間の無駄ですので、少しずるい方法をとることにします。すべてのオプションに、そのフォント名と一致する ID を与えるのです。これにより、"all" コレクションで Internet Explorer のインデキシング メソッドを使って、要素を ID をもとに簡単に調べるすることができます。目的のオプションが得られたら、選択された値を true に変更するだけで、更新されたフォントのドロップダウン ボックスが得られます。
結論
これで今月の DHTML Dude コラムは終わりです。今回取り上げた 2 つの機能には、あまり関連性はありませんが、どちらもきわめて強力です。CSS Positioning を使用する人にとっては、座標系の動作と、ローカル座標、ウィンドウ座標、スクリーン座標の間の変換方法を理解しておくことが非常に役立ちます。
一方、Internet Explorer が内蔵している編集サポートは、見過ごされやすいとはいえ、きわめて強力です。編集機能を、Internet Explorer のその他のリッチなオブジェクト モデル サポートと組み合わせることで、友人の C++ プログラマも驚くようなリッチなアプリケーションを作成することができます。
Michael Wallent は、Microsoft の Internet Explorer 担当の Product Unit マネージャです。