コンテンツに基づいて iframe のサイズを変更する
-
03-07-2019 - |
質問
私は iGoogle のようなアプリケーションに取り組んでいます。他のアプリケーション (他のドメイン上) からのコンテンツは、iframe を使用して表示されます。
iframe のコンテンツの高さに合わせて iframe のサイズを変更するにはどうすればよいですか?
Google が使用する JavaScript を解読しようとしましたが、難読化されており、Web 検索は今のところ無駄です。
アップデート: コンテンツは他のドメインからロードされるため、 同一生成元ポリシー が適用されます。
解決
この種の問題はありましたが、あなたの状況とはわずかに逆でした。他のドメインのサイトにiframedコンテンツを提供していたため、同じオリジンポリシーも問題でした。 Googleのトロールに何時間も費やした後、最終的に(ある程度)実行可能なソリューションが見つかりました。これは、ニーズに適応できる場合があります。
同じ発信元ポリシーを回避する方法がありますが、iframeされたコンテンツとフレーミングページの両方で変更が必要であるため、両側で変更を要求する機能がない場合、このメソッドはあまり役に立ちません。あなたには、私は恐れています。
同じ起源ポリシーを回避できるブラウザの癖があります-javascriptは、独自のドメイン上のページまたはiframeされたページと通信できますが、フレーム化されたページとは通信できません持っている場合:
www.foo.com/home.html, which iframes
|-> www.bar.net/framed.html, which iframes
|-> www.foo.com/helper.html
then home.html
は、framed.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 |
+-------------------------+-----------+-------------+-------------+
src=''
はメッセージをonload
(iframed)に送信できますが、はできません helper.html?height=N
(子はクロスドメインを親と通信できません)。
ここで重要なのは、www.foo.com/home.html
がwww.bar.net/framed.html
からメッセージを受信でき、はwww.foo.com/helper.html
と通信することもできます。
したがって、本質的に、<=>が読み込まれると、独自の高さを算出し、<=>に伝え、メッセージを<=>に渡します。これにより、<=>が置かれているiframeのサイズを変更できます。
<=>から<=>にメッセージを渡す最も簡単な方法は、URL引数を使用することです。これを行うには、<=>に<=>が指定されたiframeがあります。 <=>が起動すると、自身の高さを評価し、この時点でiframeのsrcを<=>
に設定しますここに説明があります facebookがそれを処理します。これは上記のものよりもわずかに明確かもしれません!
コード
<=>では、次の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>
<=>内:
<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>
<=>の内容:
<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>
他のヒント
別のドメインの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>
https://developer.mozilla.org/en/DOM/window.postMessage
window.postMessage()
window.postMessageは、クロスオリジン通信を安全に有効にする方法です。通常、異なるページのスクリプトは、それらを実行したページが同じプロトコル(通常は両方ともhttp)、ポート番号(80がhttpのデフォルト)、およびホスト(モジュロ)の場所にある場合にのみ、互いにアクセスできますdocument.domainは両方のページで同じ値に設定されています)。 window.postMessageは、適切に使用された場合に安全な方法でこの制限を回避するための制御されたメカニズムを提供します。
概要
window.postMessageが呼び出されると、実行する必要のある保留中のスクリプトが完了すると、ターゲットウィンドウでMessageEventがディスパッチされます(window.postMessageがイベントハンドラーから呼び出された場合、残りのイベントハンドラー、事前に設定された保留タイムアウトなど)。 MessageEventには、タイプメッセージ、window.postMessageに提供される最初の引数の文字列値に設定されるデータプロパティ、時間ウィンドウでwindow.postMessageを呼び出すウィンドウ内のメインドキュメントの発信元に対応する発信元プロパティがあります。 postMessageが呼び出され、window.postMessageが呼び出されるウィンドウであるソースプロパティ。 (イベントのその他の標準プロパティは、期待される値とともに存在します。)
iFrame-Resizer ライブラリは、 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ワーキングドラフト
クロスウィンドウメッセージングのJohn Resig
jQueryを使用する最も簡単な方法:
$("iframe")
.attr({"scrolling": "no", "src":"http://www.someotherlink.com/"})
.load(function() {
$(this).css("height", $(this).contents().height() + "px");
});
解決策は、 http://www.phinesolutions.com/use-jquery-to-adjust-the-iframe-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」。これはあなたが望んでいることではないかもしれません。
他のすべての回答が古いため、少し遅れる可能性があります:-)しかし...ここ<!>#180; s私の解決策です。実際の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
});
});
});
これが誰にも役立つことを願っています。
最後に、window.postMessage(message, targetOrigin);
を使用してiframeから親Webサイトにデータを送信する他のソリューションを見つけました。ここで、私がどのようにしたかを説明します。
サイトA = http://foo.com サイトB = http://bar.com
SiteBはsiteA Webサイト内にロードしています
SiteB Webサイトにはこの行があります
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);
セキュリティ接続を追加する場合は、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);
これは、iframeコンテンツと同じサーバーが提供する動的に生成されたスタイルシートを使用した簡単なソリューションです。簡単に言うと、スタイルシート<!> quot; knows <!> quot; 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のレンダリングされたコンテンツの寸法を計算できるサーバー側のロジックが必要です。
この回答は、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/
ConroyPのフレームインフレームソリューションを実装してdocument.domainの設定に基づいたソリューションを置き換えていますが、異なるブラウザーで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()はブラウザ検出機能<!> quot; inspired <!> quot; Ext Coreの http://docs.sencha.com/core/ source / Ext.html#method-Ext-apply
これはFFとIEではうまく機能しましたが、Chromeには問題がありました。その1つはタイミングの問題でした。明らかに、iframeの高さを設定/検出するにはChromeに時間がかかります。また、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);
}
コードは最適化されていません、それは私の開発テストからです:)
誰かがこれを助けてくれることを願っています!
<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>
iGoogleガジェットは、サイズ変更を積極的に実装する必要があるため、リモートコンテンツが何らかの形で参加しなければ、これを行うことができないクロスドメインモデルであると推測します。コンテンツが一般的なクロスドメイン通信技術を使用して新しいサイズのメッセージをコンテナページに送信できる場合、残りは簡単です。
Webページをiframeサイズに合わせて縮小する場合:
- コンテンツに合わせて iframe のサイズを変更する必要があります
- 次に、読み込まれた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>
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);
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);
}
ロード時に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);
}
});
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>
iframeページがいつ読み込まれたかを知る必要があるため、これは少し注意が必要です。これは、コンテンツを制御していない場合は困難です。 iframeにonloadハンドラーを追加することは可能ですが、過去にこれを試しましたが、ブラウザー間で動作が大きく異なります(誰が最も迷惑なのか推測できません...)。サイズ変更を実行し、ロードイベントをリッスンするか、イベントをサイズ変更するコンテンツにスクリプトを挿入する関数をiframeページに追加する必要があります。これにより、前の関数が呼び出されます。セキュリティを確保したいので、ページに関数を追加することを考えていますが、それがどれほど簡単になるかわかりません。
この行の何かがうまくいくと思う。
parent.document.getElementById(iFrameID).style.height=framedPage.scrollHeight;
iframeコンテンツのボディオンロードでこれをロードします。
簡単な解決策があり、リンクの幅と高さを決定する必要があります、試してください(ほとんどのブラウザで動作します):
<a href='#' onClick=" document.getElementById('myform').src='t2.htm';document.getElementById('myform').width='500px'; document.getElementById('myform').height='400px'; return false">500x400</a>