IFrameオブジェクト

IFrameオブジェクトの取得

IFrameオブジェクトは、その取得方法によって異なるオブジェクトとなります。

取得方法 返されるオブジェクト
Window.frames[] Window
Name (name属性の値)
Document.getElementById( ID ) IFrame
Document.getElementsByTagName( 'iframe' )
ID (id属性の値で宣言されたグローバル変数) ※1 [非標準]
※1 Internet Explorerでは、IFrameではなくWindowオブジェクト

IFrameオブジェクトとして取得しないと、このページで解説する方法を適用できません。もしWindowオブジェクトが必要ならば、IFrameオブジェクトからでも

のいずれかの方法で取得できます。

プロパティ

プロパティ 内容
Document contentDocument iframe要素のHTMLドキュメント
Window contentWindow iframe要素のウィンドウ
String src iframe要素のsrc属性の内容
String width  
String height  
String frameBorder  
Properties - HTMLIFrameElement - Web APIs | MDN

contentDocument

IE8より前はcontentDocumentをサポートしないため、それにも対応させるためにはIFrame.contentWindow.documentを使用します。よってクロスブラウザとするには、

var contentDocument
 = IFrame.contentDocument || IFrame.contentWindow.document;

とします。contentDocument property (Internet Explorer) | MSDN

body要素へのアクセス

IFrameのbody要素へは、Iframe.contentDocument.bodyでアクセスできます。

取得タイミング

contentDocumentは、IFrameオブジェクトがドキュメントに追加されるまではnullを返します。

var iframe  =  document.createElement( 'iframe' );
console.log('1:' + iframe.contentDocument);

iframe.src='/';
console.log('2:' + iframe.contentDocument);

iframe.onload = function(e)
{
    console.log('3:' + iframe.contentDocument);
}

document.body.appendChild(iframe);
console.log('4:' + iframe.contentDocument);

// 1:null
// 2:null
// 4:[object HTMLDocument]
// 3:[object HTMLDocument]

外部サイトのドキュメントへのアクセス

contentDocumentへのアクセスには同一起源ポリシーによる制約を受けます。そのためiframeにより埋め込まれた外部サイトの内容を、スクリプトで改変するようなことはできません。

外部サイトのcontentDocumentを読み込もうとすると、ブラウザごとに下表のような反応を示します。

ブラウザ  
Internet Explorer 11 例外が発生する。
  • code … 0x80070005 (-2147024891)
  • message … "アクセスが拒否されました。\r\n"。
Chrome 例外が発生する。
  • code … 18
  • message … "Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://example.com" from accessing a cross-origin frame."。
Firefox nullが返される。 例外が発生する。
  • message … "Permission denied to access property "document""

この制約はフレーム内のウィンドウに対しても同様で、srcプロパティで外部サイトを指定した場合、その外部サイトからwindow.parentを介してアクセスされることはありません。

src

このプロパティを変更すると、フレーム内に新しいドキュメントが読み込まれます。ただしX-Frame-Optionsヘッダが出力されるページは表示できません。

srcプロパティはただの文字列であるStringオブジェクトであり、Locationオブジェクトではありません。

イベント

onload

onloadイベントは、src属性により指定されたリソースの読み込み完了時に発生します。しかしHTMLで記述したiframe要素が読み込まれるタイミングは予測できないため、HTMLの属性としてハンドラを記述するのが確実です。

<iframe onload="alert( '完了' )" src="http://example.com"></iframe>

なお、ハンドラ内でのthisキーワードはWindowオブジェクトです。

iframeの内容を動的に読み込む場合

iframeの内容を動的に読み込み、その読み込み完了時に何らかの処理をする場合を考えます。このときiframeのonloadイベントに設定するだけでは、ページの読み込み時にもイベントが発生してしまいます。よってWindow.onloadイベント発生時に、IFrame.onloadイベントを設定するようにします。

<iframe name="frameName" id="frameId"></iframe>

<form target="frameName" action="sample.htm" method="get">
    <input type="submit" value="読み込む" />
</form>

<script type="text/javascript">
  window.onload = function()
  {
      var iframe = document.getElementById( 'frameId' );
      iframe.onload = function()
      {
          alert( '読み込み完了' );
      }
  }
</script>

onerror

iframeではerrorイベントを捕捉できません。javascript - How can I handle errors in loading an iframe? - Stack Overflow

他のIFrameへのアクセス

iframe要素内から、他のiframe要素内へアクセスする場合を考えます。それらの要素は、

<iframe id="frame1" src="frame1.htm"></iframe>
<iframe id="frame2" src="frame2.htm"></iframe>
<div>
    parent Window
    <input type="text" id="text" readonly="readonly" />
</div>

のように配置されているものとします。また読み込まれるフレーム内には、

frame1<input type="text" id="text" value="" />

の記述があるものとします。このとき1つ目のiframe内で、

// 親ウィンドウのドキュメントを取得する
var parentDocument = window.parent.document;

// 親ウィンドウのドキュメント内で、他のiframeをIDから取得する
var frame2 = parentDocument.getElementById( 'frame2' );

// 他のiframeのドキュメントを取得する
var otherDocument = frame2.contentWindow.document;
otherDocument.getElementById( 'text' ).value = 'TEST';

とすることで、2つ目のiframe内の要素にアクセスできます。

実行例

frame1、frame2のテキストボックスへの入力を、それぞれ他方へコピーします。また同時に、親となるウィンドウのテキストボックスへもコピーします。

下のフレーム内のテキストボックスへ、文字を入力してください。
parent Window

親ウィンドウとiframe要素内のウィンドウが同一起源ポリシーを満足していないと、このように親ウィンドウを介してアクセスすることはできません。

フレーム内のコンテンツのサイズに合わせて、フレームのサイズを調整する

フレーム内のコンテンツがフレームより大きいとスクロールしなければ閲覧できず、一方でフレームより小さいと無駄な余白が生じます。これをフレーム内のコンテンツのサイズに合わせて、フレーム自身のサイズを調整する方法を考えます。

コンテンツのサイズはリソースの読み込み後に確定するため、onloadイベントで処理します。

iframe.onload = function()
{
    var contentDocument = this.contentDocument || this.contentWindow.document;

    this.width = contentDocument.documentElement.scrollWidth;
    this.height = contentDocument.documentElement.scrollHeight;
}

なおこの方法はcontentDocumentへのアクセスを伴うため、外部サイトのドキュメントに対しては適用できません。

参考

参考書

  • JavaScript 第5版 [オライリー・ジャパン] David Flanagan
    14章8「複数のウィンドウとフレーム」Frame要素の解説ですが、参考になります。
JavaScriptのドキュメントから検索