コンテンツに基づいてiframeのサイズを変更する


498

私はiGoogleのようなアプリケーションに取り組んでいます。他のアプリケーション(他のドメイン上)のコンテンツは、iframeを使用して表示されます。

iframeのコンテンツの高さに合わせてiframeのサイズを変更するにはどうすればよいですか?

私はGoogleが使用するJavaScriptを解読しようとしましたが、難読化されており、Webの検索はこれまでのところ無意味でした。

更新:コンテンツは他のドメインから読み込まれるため、同一生成元ポリシーが適用されることに注意してください。

回答:


584

この種の問題がありましたが、状況とは少し逆です。他のドメインのサイトにiframe化されたコンテンツを提供していたため、同じ生成元ポリシーも問題でした。グーグルの調査に何時間も費やした後、最終的に(ある程度..)実行可能なソリューションが見つかりました。これは、ニーズに適応できる可能性があります。

同じオリジンポリシーを回避する方法はありますが、iFrameされたコンテンツとフレーミングページの両方で変更を行う必要があるため、両側で変更を要求する機能がない場合、この方法はあまり役に立ちません。私は怖いです。

同じオリジンポリシーを回避できるブラウザの癖があります。JavaScriptは、独自のドメインのページまたはフレーム化されたページと通信できますが、フレーム化されたページとは通信できません。

 www.foo.com/home.html, which iframes
 |-> www.bar.net/framed.html, which iframes
     |-> www.foo.com/helper.html

その後home.htmlframed.html(iframed)およびhelper.html(同じドメイン)と通信できます。

 Communication options for each page:
 +-------------------------+-----------+-------------+-------------+
 |                         | home.html | framed.html | helper.html |
 +-------------------------+-----------+-------------+-------------+
 | www.foo.com/home.html   |    N/A    |     YES     |     YES     |
 | www.bar.net/framed.html |    NO     |     N/A     |     YES     |
 | www.foo.com/helper.html |    YES    |     YES     |     N/A     |
 +-------------------------+-----------+-------------+-------------+

framed.htmlhelper.html(iframed)にはメッセージを送信できますが home.html(子は親とクロスドメインで通信できません)。

ここで重要なのはそれがあるhelper.htmlからメッセージを受信することができframed.html、そしてまた、通信することができhome.html

したがって、基本的には、framed.htmlロード時に独自の高さhelper.htmlを計算し、に通知します。home.htmlこれにより、にメッセージが渡され、framed.html座っているiframeのサイズを変更できます。

からframed.htmlにメッセージを渡す最も簡単な方法はhelper.html、URL引数を使用することでした。これを行うにframed.htmlは、src=''指定されたiframeがあります。そのときonload火災は、それはそれ自身の高さを評価し、この時点でのiframeのSRCを設定し、helper.html?height=N

facebookがそれをどのように処理するかについての説明がここにあります。これは、上記のものより少し明確かもしれません!


コード

ではwww.foo.com/home.html、次のjavascriptコードが必要です(これは、偶然にも、任意のドメインの.jsファイルからロードできます。)。

<script>
  // Resize iframe to full height
  function resizeIframe(height)
  {
    // "+60" is a general rule of thumb to allow for differences in
    // IE & and FF height reporting, can be adjusted as required..
    document.getElementById('frame_name_here').height = parseInt(height)+60;
  }
</script>
<iframe id='frame_name_here' src='http://www.bar.net/framed.html'></iframe>

www.bar.net/framed.html

<body onload="iframeResizePipe()">
<iframe id="helpframe" src='' height='0' width='0' frameborder='0'></iframe>

<script type="text/javascript">
  function iframeResizePipe()
  {
     // What's the page height?
     var height = document.body.scrollHeight;

     // Going to 'pipe' the data to the parent through the helpframe..
     var pipe = document.getElementById('helpframe');

     // Cachebuster a precaution here to stop browser caching interfering
     pipe.src = 'http://www.foo.com/helper.html?height='+height+'&cacheb='+Math.random();

  }
</script>

の内容www.foo.com/helper.html

<html> 
<!-- 
This page is on the same domain as the parent, so can
communicate with it to order the iframe window resizing
to fit the content 
--> 
  <body onload="parentIframeResize()"> 
    <script> 
      // Tell the parent iframe what height the iframe needs to be
      function parentIframeResize()
      {
         var height = getParam('height');
         // This works as our parent's parent is on our domain..
         parent.parent.resizeIframe(height);
      }

      // Helper function, parse param from request string
      function getParam( name )
      {
        name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
        var regexS = "[\\?&]"+name+"=([^&#]*)";
        var regex = new RegExp( regexS );
        var results = regex.exec( window.location.href );
        if( results == null )
          return "";
        else
          return results[1];
      }
    </script> 
  </body> 
</html>

7
洞察に満ち溢れています。なぜigoogle.comにhelper.htmlファイルがあったのかと思っていました。ありがとう
IEnumerator

9
素晴らしいです、ありがとう!私はいくつか追加しました:jQueryを使用してframed.htmlのボディの高さを取得します(FFの問題、ボディは成長し続けます):var height = $(document.body).height(); body onloadイベントを使用して、framed.htmlでのアプローチと同様に、home.htmlでフレームを作成しました。FFおよびSafariでリフレッシュ時にフレームを更新しないアドレス。
アブドラジバリー2009

5
天才!Abdullahの追加に加えて、body onloadをcallに設定するのではなく、parentIframeResize()JQueryを使用して、ページの読み込みとサイズ変更イベントの両方をキャッチしました。$(document).ready(iframeResizePipe); $(window).resize(iframeResizePipe);これにより、iframeを設定しwidth="100%"、ウィンドウの幅を変更してテキストを折り返すか何かを設定することができます。内部フレームは、サイズを変更する必要があることを認識します。
StriplingWarrior 2010年

9
iframe id = frame_name_hereに、height = "2000"などのデフォルトの高さ属性を指定することをお勧めします。つまり、ページが読み込まれると、フレーム化されたコンテンツが表示されます。サイズ変更が発生しても、「ちらつき」はありません。サイズ変更はページの折り目の下で縮小/拡大しています。iframedコンテンツの最大の高さがわかっている場合は、その値を使用してください。これにより、noscriptエクスペリエンスが向上します。
Chris Jacob

3
7年後も、私が見つけた最高のクロスブラウザー、クロスドメインソリューションです。ブラボー。
FurryWombat 2015年

81

別のドメインのiframeコンテンツを処理する必要がない場合は、次のコードを試してください。問題が完全に解決され、簡単です。

<script language="JavaScript">
<!--
function autoResize(id){
    var newheight;
    var newwidth;

    if(document.getElementById){
        newheight=document.getElementById(id).contentWindow.document .body.scrollHeight;
        newwidth=document.getElementById(id).contentWindow.document .body.scrollWidth;
    }

    document.getElementById(id).height= (newheight) + "px";
    document.getElementById(id).width= (newwidth) + "px";
}
//-->
</script>

<iframe src="usagelogs/default.aspx" width="100%" height="200px" id="iframe1" marginheight="0" frameborder="0" onLoad="autoResize('iframe1');"></iframe>

9
要素自体を関数に渡して、これらdocument.getElementById(id)のsをすべて回避し、コードを簡略化する方が最適な場合があります。
Muhd、2011年

1
contentWindow.document.body.scrollHeightは実際の高さではなく0を保持するため、これは私には機能しません。
kroiz

4
この解決策は、私が試した他のすべての解決策と同様に、高さが増加した場合にのみ機能します。背の高いページから短いページに移動しても、高さは最初のページの高さに従って設定されます。誰かがこの問題の解決策を見つけましたか?
Eugenio

6
@Eugenioと私を含むすべての人がこの最終的な問題を修正するには、stackoverflow.com / questions / 3053072 /…を参照してください。iframe 内のドキュメントの高さを要求する前に、iframeオブジェクトの高さを「auto」に設定する必要があります。あなたは上記の回答でようstyle.heightだけでなく、高さを使用する必要があることを注意
カイル

7
取得できません... document.getElementByIdの存在を確認してから、チェックされた領域の外で呼び出しますか?
レゴラス2013

41

https://developer.mozilla.org/en/DOM/window.postMessage

window.postMessage()

window.postMessageは、クロスオリジン通信を安全に有効にするためのメソッドです。通常、異なるページのスクリプトは、それらを実行したページが同じプロトコル(通常はhttpの両方)、ポート番号(httpのデフォルトは80)、およびホスト(modulo)の場所にある場合にのみ、相互にアクセスできます。 document.domainは両方のページで同じ値に設定されています)。window.postMessageは、適切に使用したときに安全な方法でこの制限を回避するための制御されたメカニズムを提供します。

概要

window.postMessageが呼び出されると、実行する必要のある保留中のスクリプトが完了すると、ターゲットウィンドウでMessageEventが送出されます(たとえば、イベントハンドラーからwindow.postMessageが呼び出された場合の残りのイベントハンドラー、以前に設定された保留中のタイムアウトなど)。 )。MessageEventにはメッセージタイプ、つまりwindow.postMessageに提供された最初の引数の文字列値に設定されるデータプロパティ、タイムウィンドウでwindow.postMessageを呼び出すウィンドウのメインドキュメントの起点に対応する起点プロパティがあります。 postMessageが呼び出され、window.postMessageが呼び出されたウィンドウであるソースプロパティ。(イベントの他の標準プロパティは、それらの期待値とともに存在します。)

iFrameの-リサイズのライブラリはと一緒に、それの内容にサイズのiFrameを維持するためのpostMessageを使用していますMutationObserverコンテンツへの変更を検出するとjQueryには依存しません。

https://github.com/davidjbradshaw/iframe-resizer

jQuery:クロスドメインスクリプティングの良さ

http://benalman.com/projects/jquery-postmessage-plugin/

iframeウィンドウのサイズ変更のデモがあります...

http://benalman.com/code/projects/jquery-postmessage/examples/iframe/

この記事では、jQueryへの依存関係を削除する方法を示します... Plusには、多くの役立つ情報と他のソリューションへのリンクがあります。

http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/

ベアボーンの例...

http://onlineaspect.com/uploads/postmessage/parent.html

window.postMessageのHTML 5ワーキングドラフト

http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages

クロスウィンドウメッセージングに関するJohn Resig

http://ejohn.org/blog/cross-window-messaging/


postMessage自体はクロスブラウザではありませんが、jQueryプラグインは必要に応じてそれをだますのに良い仕事をしているようです。実際の問題は、postMessageがサポートされていない場合にURLバーに追加される「ジャンク」だけです。
Herms

2
postMessageはX-Browserのようです。IEのみがバグや注意事項を備えている必要があります。1.フレームまたはiframe間の通信のみ2.文字列の投稿のみが可能です。参照:caniuse.com/x-doc-messaging
Christian Kuetbach

3
..あなたが質問代わりの解決に役立つ支援技術について説明を答える見て素敵だっただろう
hitautodestruct

periscopedataはpostMessageを使用しています。それらに十分であれば、私たちには十分です。ドキュメントは次のとおり
Yevgeniy Afanasyev

8

jQueryを使用する最も簡単な方法:

$("iframe")
.attr({"scrolling": "no", "src":"http://www.someotherlink.com/"})
.load(function() {
    $(this).css("height", $(this).contents().height() + "px");
});

14
要求されたドメインを越えません。
ウィレム2013

6

http://www.phinesolutions.com/use-jquery-to-adjust-the-if​​rame-height.htmlのソリューションはうまく機能します(jQueryを使用):

<script type=”text/javascript”>
  $(document).ready(function() {
    var theFrame = $(”#iFrameToAdjust”, parent.document.body);
    theFrame.height($(document.body).height() + 30);
  });
</script>

長さに30を追加する必要があることを知りません... 1がうまくいきました。

参考:iFrameに「height」属性がすでにある場合は、style = "height:xxx"が追加されます。これはあなたが望むものではないかもしれません。


7
クロスドメインではありません。
Volomike

クロスドメインではないので、必要なものだけです。有効なhtmlの+1です。
WildJoe、2011年

4

他のすべての回答が古いため、少し遅れる可能性があります:-)しかし...これが私の解決策です。実際のFF、Chrome、Safari 5.0でテスト済み。

css:

iframe {border:0; overflow:hidden;}

javascript:

$(document).ready(function(){
    $("iframe").load( function () {
        var c = (this.contentWindow || this.contentDocument);
        if (c.document) d = c.document;
        var ih = $(d).outerHeight();
        var iw = $(d).outerWidth();
        $(this).css({
            height: ih,
            width: iw
        });
    });
});

これが誰かを助けることを願っています。


@pashute-「クロスドメイン」という意味ですか?
ルーク、

ごめんなさい。意味:クロスプラットフォームで動作しません...公開要旨は次のとおりです:gist.github.com/pashute/c4705ce7f767f50fdf56d0030ecf9192 Refused to executeエラーを取得します。type = "text / javascript"を持つようにスクリプトを変更しても、役に立ちません。iframeの幅と高さ(たとえば80%)も設定しません。
パシュテ

4

最後に、iframeから親Webサイトにデータを送信するための他の解決策を見つけました window.postMessage(message, targetOrigin);。ここで私はどのようにしたかを説明します。

サイトA = http://foo.com サイトB = http://bar.com

SiteBがsiteAウェブサイト内に読み込まれている

SiteBウェブサイトにはこの行があります

window.parent.postMessage("Hello From IFrame", "*"); 

または

window.parent.postMessage("Hello From IFrame", "http://foo.com");

次に、siteAは次のコードを持っています

// Here "addEventListener" is for standards-compliant web browsers and "attachEvent" is for IE Browsers.
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];


var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

// Listen to message from child IFrame window
eventer(messageEvent, function (e) {
   alert(e.data);
   // Do whatever you want to do with the data got from IFrame in Parent form.
}, false); 

セキュリティ接続を追加したい場合は、このif条件を使用できます eventer(messageEvent, function (e) {})

if (e.origin == 'http://iframe.example.com') {
    alert(e.data); 
    // Do whatever you want to do with the data got from IFrame in Parent form.
}

IEの場合

IFrame内:

 window.parent.postMessage('{"key":"value"}','*');

外側:

 eventer(messageEvent, function (e) {
   var data = jQuery.parseJSON(e.data);
   doSomething(data.key);
 }, false);

2

これは、iframeコンテンツと同じサーバーによって提供される動的に生成されたスタイルシートを使用した簡単なソリューションです。スタイルシートは、iframeの内容を "認識"しており、iframeのスタイルを設定するために使用する寸法を認識しています。これは、同じ発信元ポリシーの制限を回避します。

http://www.8degrees.co.nz/2010/06/09/dynamically-resize-an-iframe-depending-on-its-content/

したがって、提供されるiframeコードには、次のようなスタイルシートが付随します。

<link href="http://your.site/path/to/css?contents_id=1234&dom_id=iframe_widget" rel="stylesheet" type="text/css" />
 <iframe id="iframe_widget" src="http://your.site/path/to/content?content_id=1234" frameborder="0" width="100%" scrolling="no"></iframe>

これには、サーバー側のロジックがiframeのレンダリングされたコンテンツのサイズを計算できる必要があります。


リンクがダウンしています。このスレッドに引き続き関連するように、回答で関連するコードを共有していただけませんか?
ZED

2

この回答は、Bootstrapを使用するWebサイトにのみ適用されます。Bootstrapのレスポンシブ埋め込み機能がその役割を果たします。コンテンツの幅(高さではない)に基づいています。

<!-- 16:9 aspect ratio -->
<div class="embed-responsive embed-responsive-16by9">
  <iframe class="embed-responsive-item" src="http://www.youtube.com/embed/WsFWhL4Y84Y"></iframe>
</div>

jsfiddle:http ://jsfiddle.net/00qggsjj/2/

http://getbootstrap.com/components/#sensitive-embed


これはビデオを埋め込むために機能しますが、高さのあるWebページを埋め込みたい場合、スクロールして奇妙な高さになります。
cabaji99

1

document.domainの設定に基づいてソリューションを置き換えるためにConroyPのフレームインフレームソリューションを実装していますが、さまざまなブラウザーでiframeのコンテンツの高さを正しく判断するのが非常に難しいことがわかりました(現在FF11、Ch17、IE9でテストしています) )。

ConroyPは以下を使用します:

var height = document.body.scrollHeight;

ただし、これは最初のページの読み込みでのみ機能します。iframeに動的コンテンツがあり、特定のイベントでiframeのサイズを変更する必要があります。

私がやったことは、ブラウザーごとに異なるJSプロパティを使用することでした。

function getDim () {
    var body = document.body,
        html = document.documentElement;

    var bc = body.clientHeight;
    var bo = body.offsetHeight;
    var bs = body.scrollHeight;
    var hc = html.clientHeight;
    var ho = html.offsetHeight;
    var hs = html.scrollHeight;

    var h = Math.max(bc, bo, bs, hc, hs, ho);

    var bd = getBrowserData();

    // Select height property to use depending on browser
    if (bd.isGecko) {
        // FF 11
        h = hc;
    } else if (bd.isChrome) {
        // CH 17
        h = hc;
    } else if (bd.isIE) {
        // IE 9
        h = bs;
    }

    return h;
}

getBrowserData()は、Ext Coreのhttp://docs.sencha.com/core/source/Ext.html#method-Ext-applyにインスパイアされたブラウザ検出関数です

これはFFとIEではうまく機能しましたが、Chromeで問題が発生しました。その1つはタイミングの問題でした。どうやらChromeでiframeの高さを設定/検出するにはしばらく時間がかかります。また、iframeがコンテンツよりも高い場合、Chromeはiframeのコンテンツの高さを正しく返しませんでした。これは、高さが低くなると動的コンテンツでは機能しません。

これを解決するには、コンテンツの高さを検出する前に常にiframeを低い高さに設定し、iframeの高さを正しい値に設定します。

function resize () {
    // Reset the iframes height to a low value.
    // Otherwise Chrome won't detect the content height of the iframe.
    setIframeHeight(150);

    // Delay getting the dimensions because Chrome needs
    // a few moments to get the correct height.
    setTimeout("getDimAndResize()", 100);
}

コードは最適化されていません、それは私の開発テストからです:)

これが役立つと誰かが願っています!


1
<html>
<head>
<script>
function frameSize(id){
var frameHeight;

document.getElementById(id).height=0 + "px";
if(document.getElementById){
    newheight=document.getElementById(id).contentWindow.document.body.scrollHeight;    
}

document.getElementById(id).height= (frameHeight) + "px";
}
</script>
</head>

<body>

<iframe id="frame"  src="startframe.html" frameborder="0" marginheight="0" hspace=20     width="100%" 

onload="javascript:frameSize('frame');">

<p>This will work, but you need to host it on an http server, you can do it locally.    </p>
</body>
</html>

0

iGoogleガジェットは積極的にサイズ変更を実装する必要があるので、リモートドメインが何らかの形で参加しなければ、クロスドメインモデルではこれを実行できないと思います。コンテンツが通常のクロスドメイン通信技術を使用して新しいサイズのメッセージをコンテナページに送信できる場合、残りは簡単です。


0

Webページを縮小してiframeサイズに合わせる場合:

  1. iframeのサイズを変更する必要がありますコンテンツに合わせてがあります
  2. 次に、読み込まれたWebページのコンテンツでiframe全体をズームアウトする必要があります

次に例を示します。

<div id="wrap">
   <IFRAME ID="frame" name="Main" src ="http://www.google.com" />
</div>

<style type="text/css">
    #wrap { width: 130px; height: 130px; padding: 0; overflow: hidden; }
    #frame { width: 900px; height: 600px; border: 1px solid black; }
    #frame { zoom:0.15; -moz-transform:scale(0.15);-moz-transform-origin: 0 0; }
</style>

0

以下は、iframeのsrc属性を介してjsonに情報を追加するjQueryアプローチです。これがデモです。このウィンドウのサイズを変更してスクロールします。jsonを使用した結果のURLは次のようになります... http://fiddle.jshell.net/zippyskippy/RJN3G/show/#{docHeight:5124,windowHeight:1019,scrollHeight: 571}#

ここにソースコードフィドルがありますhttp://jsfiddle.net/zippyskippy/RJN3G/

function updateLocation(){

    var loc = window.location.href;
    window.location.href = loc.replace(/#{.*}#/,"") 
        + "#{docHeight:"+$(document).height() 
        + ",windowHeight:"+$(window).height()
        + ",scrollHeight:"+$(window).scrollTop()
        +"}#";

};

//setInterval(updateLocation,500);

$(window).resize(updateLocation);
$(window).scroll(updateLocation);

0

iframeコンテンツの高さを取得して、このiframeに渡します

 var iframes = document.getElementsByTagName("iframe");
 for(var i = 0, len = iframes.length; i<len; i++){
      window.frames[i].onload = function(_i){
           return function(){
                     iframes[_i].style.height = window.frames[_i].document.body.scrollHeight + "px";
                     }
      }(i);
 }

1
あなたのコードが質問に答える理由について、何らかの説明を追加できますか?
rhughes 2013

0

ロード時にjqueryを操作する(クロスブラウザー):

 <iframe src="your_url" marginwidth="0"  marginheight="0" scrolling="No" frameborder="0"  hspace="0" vspace="0" id="containiframe" onload="loaderIframe();" height="100%"  width="100%"></iframe>

function loaderIframe(){
var heightIframe = $('#containiframe').contents().find('body').height();
$('#frame').css("height", heightFrame);
 }  

レスポンシブページのサイズ変更時:

$(window).resize(function(){
if($('#containiframe').length !== 0) {
var heightIframe = $('#containiframe').contents().find('body').height();
 $('#frame').css("height", heightFrame);
}
});

-1

jQueryの使用:

parent.html

<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<style>
iframe {
    width: 100%;
    border: 1px solid black;
}
</style>
<script>
function foo(w, h) {
    $("iframe").css({width: w, height: h});
    return true;  // for debug purposes
}
</script>
<iframe src="child.html"></iframe>
</body>

child.html

<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
$(function() {
    var w = $("#container").css("width");
    var h = $("#container").css("height");

    var req = parent.foo(w, h);
    console.log(req); // for debug purposes
});
</script>
<style>
body, html {
    margin: 0;
}
#container {
    width: 500px;
    height: 500px;
    background-color: red;
}
</style>
<div id="container"></div>
</body>

-2

iframeページがいつ読み込まれたかを知る必要があるため、これは少し注意が必要です。これは、コンテンツを制御していない場合は困難です。iframeにonloadハンドラーを追加することは可能ですが、これを以前に試したことがあり、ブラウザーによって動作が大きく異なります(誰が最も迷惑なのかはわかりません...)。おそらく、サイズ変更を実行するiframeページに関数を追加し、ロードイベントまたはサイズ変更イベントをリッスンするコンテンツにスクリプトを挿入してから、前の関数を呼び出す必要があります。安全を確保したいので、ページに関数を追加することを考えていますが、それがどれほど簡単かはわかりません。


-2

これの私が信じている何かがうまくいくはずです。

parent.document.getElementById(iFrameID).style.height=framedPage.scrollHeight;

これをiframeコンテンツのonloadでロードします。


3
iFrameのコンテンツは他のドメインから読み込まれるため、これを行うことはできません。そのようにすると、Firefoxからのエラー「プロパティWindow.documentの取得が拒否されました」などのエラーが発生します。
larssg 2008

-4

簡単な解決策があり、リンクの幅と高さを決定する必要があります。試してみてください(ほとんどのブラウザーで動作します)。

<a href='#' onClick=" document.getElementById('myform').src='t2.htm';document.getElementById('myform').width='500px'; document.getElementById('myform').height='400px'; return false">500x400</a>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.