Redimensionnement d'une iframe basée sur le contenu
je travaille sur une application de type iGoogle. Le contenu d'autres applications (sur d'autres domaines) est affiché en utilisant iframes.
comment redimensionner les iframes en fonction de la hauteur du contenu des iframes?
j'ai essayé de déchiffrer le javascript que Google utilise, mais il est obscurci, et la recherche sur le web a été infructueuse jusqu'à présent.
mise à Jour: Veuillez noter que le contenu est chargé à partir d'autres domaines, ainsi, la Politique de même origine s'applique.
20 réponses
nous avons eu ce type de problème, mais légèrement à l'inverse de votre situation - nous fournissons le contenu iframed à des sites sur d'autres domaines, de sorte que la même politique d'origine était également un problème. Après de nombreuses heures passées à traquer google, nous avons finalement trouvé un (quelque peu..) solution réalisable, que vous pourriez être en mesure d'adapter à vos besoins.
il y a un moyen de contourner la même politique d'origine, mais il nécessite des changements à la fois sur le contenu iframed et la page de cadrage, donc si vous n'avez pas la possibilité de demander des changements des deux côtés, cette méthode ne vous sera pas très utile, j'en ai bien peur.
il y a une bizarrerie de navigateur qui nous permet de contourner la même politique d'origine-javascript peut communiquer soit avec des pages sur son propre domaine, ou avec des pages qu'il a iframed, mais jamais des pages dans lesquelles il est encadré, par exemple si vous avez:
www.foo.com/home.html, which iframes
|-> www.bar.net/framed.html, which iframes
|-> www.foo.com/helper.html
puis home.html
peut communiquer avec framed.html
(iframed) et helper.html
(même domaine).
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.html
peut envoyer des messages à helper.html
(iframed) mais pas home.html
(l'enfant ne peut pas communiquer de domaine croisé avec le parent).
la clé ici est que helper.html
peut recevoir des messages de framed.html
, et peut aussi communiquer avec home.html
.
donc essentiellement, quand framed.html
charges, il fonctionne de sa propre hauteur, dit helper.html
, qui passe le message à home.html
, qui peut alors redimensionner l'iframe dans laquelle framed.html
se trouve.
le moyen le plus simple que nous ayons trouvé pour passer des messages de framed.html
à helper.html
était par un argument D'URL. Pour ce faire, framed.html
a une iframe avec src=''
spécifié. Lorsque son onload
incendies, il évalue sa propre hauteur, et fixe le src de l'iframe à ce point à helper.html?height=N
Il ya une explication ici de la façon dont facebook Gérer, qui peut être un peu plus claire que la mienne ci-dessus!
Code
Dans www.foo.com/home.html
, le code javascript suivant est nécessaire (cela peut être chargé à partir d'un .js fichiers sur n'importe quel domaine d'ailleurs..):
<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>
Dans 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>
Contenu de 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>
si vous n'avez pas besoin de gérer le contenu iframe d'un autre domaine, essayez ce code, il résoudra le problème complètement et c'est simple:
<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
de la fenêtre.postMessage ()
de la fenêtre.postMessage est une méthode permettant en toute sécurité la communication d'origine croisée. Normalement, les scripts sur des pages différentes ne sont autorisés à accéder les uns aux autres que si et seulement si les pages qui les ont exécutés sont à des endroits avec le même protocole (généralement les deux http), le numéro de port (80 étant la valeur par défaut pour http), et l'hôte (modulo document.domaine défini par les deux pages de la même valeur). fenêtre.postMessage fournit un mécanisme contrôlé pour contourner cette restriction d'une manière qui est Sécuritaire lorsqu'il est correctement utilisé.
résumé
de la fenêtre.postMessage, lorsqu'il est appelé, provoque l'envoi d'un message à la fenêtre cible lorsque n'importe quel script en attente qui doit être exécuté est terminé (e.g. l'événement restant les gestionnaires si la fenêtre.postMessage est appelé à partir d'un gestionnaire d'événements, de délais en attente définis précédemment, etc.). Le MessageEvent a le message de type, une propriété de données qui est définie à la valeur de chaîne du premier argument fourni à window.postMessage, une propriété d'origine correspondant à l'origine du document principal dans la fenêtre d'appel de fenêtre.postMessage à la fenêtre horaire.postMessage a été appelé, et une propriété source qui est la fenêtre à partir de laquelle fenêtre.postMessage est appelé. (D'autres standard propriétés des événements sont présents avec leurs valeurs attendues.)
la bibliothèque iFrame-Resizer utilise postMessage pour conserver une iFrame dimensionnée à son contenu, ainsi que MutationObserver pour détecter les changements au contenu et ne dépend pas de jQuery.
https://github.com/davidjbradshaw/iframe-resizer
jQuery: cross-domain scripting bonté
http://benalman.com/projects/jquery-postmessage-plugin/
a une démo pour redimensionner la fenêtre iframe...
http://benalman.com/code/projects/jquery-postmessage/examples/iframe/
cet article montre comment supprimer la dépendance à jQuery... Plus a beaucoup d'infos utiles et des liens vers d'autres solutions.
http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/
Barebones exemple...
http://onlineaspect.com/uploads/postmessage/parent.html
HTML 5, document de travail de la fenêtre.postMessage
http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
John Resig sur la Fenêtre de Messagerie
la manière la plus simple d'utiliser jQuery:
$("iframe")
.attr({"scrolling": "no", "src":"http://www.someotherlink.com/"})
.load(function() {
$(this).css("height", $(this).contents().height() + "px");
});
La solution http://www.phinesolutions.com/use-jquery-to-adjust-the-iframe-height.html fonctionne à merveille (utilise jQuery):
<script type=”text/javascript”>
$(document).ready(function() {
var theFrame = $(”#iFrameToAdjust”, parent.document.body);
theFrame.height($(document.body).height() + 30);
});
</script>
Je ne sais pas si vous devez ajouter 30 à la longueur... 1 a fonctionné pour moi.
FYI : si vous avez déjà un attribut"height"sur votre iFrame, cela ajoute simplement style= "height: xxx". Cela pourrait ne pas être ce que vous voulez.
peut-être un peu tard, comme toutes les autres réponses sont plus :-) mais... voilà ma solution. Testé en FF, Chrome et 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
});
});
});
J'espère que ça aidera n'importe qui.
Voici une solution simple utilisant une feuille de style générée dynamiquement servie par le même serveur que le contenu iframe. Tout simplement la feuille de style "sait" ce qui est dans l'iframe, et connaît les dimensions à utiliser pour le style de l'iframe. Cela va à l'encontre des mêmes restrictions de la Politique d'origine.
http://www.8degrees.co.nz/2010/06/09/dynamically-resize-an-iframe-depending-on-its-content /
ainsi la fourniture iframe code aurait une feuille de style d'accompagnement comme cela...
<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>
cela nécessite que la logique côté serveur soit capable de calculer les dimensions du contenu rendu de l'iframe.
finalement j'ai trouvé une autre solution pour envoyer des données sur le site parent à partir d'iframe en utilisant window.postMessage(message, targetOrigin);
. Ici j'explique Comment j'ai fait.
Site = http://foo.com Site B = http://bar.com
SiteB charge à l'intérieur du site web de siteA
SiteB site Web ont cette ligne
window.parent.postMessage("Hello From IFrame", "*");
ou
window.parent.postMessage("Hello From IFrame", "http://foo.com");
puis siteA ont le code suivant:
// 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);
si vous voulez ajouter connexion de sécurité, Vous pouvez utiliser cette condition si 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.
}
Pour IE
À L'Intérieur De L'IFrame:
window.parent.postMessage('{"key":"value"}','*');
à l'extérieur:
eventer(messageEvent, function (e) {
var data = jQuery.parseJSON(e.data);
doSomething(data.key);
}, false);
cette réponse ne s'applique qu'aux sites Web qui utilisent Bootstrap. La fonction d'embed responsive du Bootstrap fait le travail. Elle est basée sur la largeur (pas la hauteur du contenu.
<!-- 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 /
J'implémente la solution frame-in-frame de ConroyP pour remplacer une solution basée sur le document de configuration.domaine, mais a trouvé assez difficile de déterminer la hauteur du contenu de l'iframe correctement dans différents navigateurs (test avec FF11, Ch17 et IE9 en ce moment).
ConroyP utilisations:
var height = document.body.scrollHeight;
mais cela ne fonctionne que sur la page de charge initiale. Mon iframe a un contenu dynamique et je dois redimensionner l'iframe sur certains événements.
ce que j'ai fini par faire était d'utiliser différentes propriétés JS pour les différents navigateurs.
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 () is browser detect function "inspired" by Ext Core http://docs.sencha.com/core/source/Ext.html#method-Ext-apply
qui a bien fonctionné pour FF et IE mais il y avait des problèmes avec Chrome. Un des était un problème de timing, apparemment, il faut Chrome un certain temps pour set/détecter la hauteur de l'iframe. Et puis Chrome n'a jamais retourné la hauteur du contenu dans l'iframe correctement si l'iframe était plus élevé que le contenu. Cela ne fonctionnerait pas avec le contenu dynamique lorsque la hauteur est réduite.
pour résoudre ce problème, je règle toujours l'iframe à une faible hauteur avant de détecter la hauteur du contenu et ensuite de régler la hauteur de l'iframe à sa valeur correcte.
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);
}
le code n'est pas optimisé, il est de mon développement test:)
Espère que quelqu'un trouve cette pratique!
<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>
gadgets iGoogle doivent activement mettre en œuvre redimensionnement, donc mon avis est dans un modèle cross-domaine, vous ne pouvez pas le faire sans le contenu à distance prendre part d'une certaine manière. Si votre contenu peut envoyer un message avec la nouvelle taille à la page du conteneur en utilisant des techniques de communication inter-domaines typiques, alors le reste est simple.
quand vous voulez zoomer sur une page web pour l'adapter à la taille iframe:
- vous devez redimensionner le iframe pour l'adapter au contenu
- ensuite, vous devriez zoomer sur l'ensemble de l'iframe avec le contenu de la page Web chargée
voici un exemple:
<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>
Voici une approche jQuery qui ajoute l'information dans json via l'attribut src de l'iframe. Voici une démo, redimensionnez et faites défiler cette fenêtre.. l'url résultante avec json ressemble à ceci... http://fiddle.jshell.net/zippyskippy/RJN3G/show/ # {docHeight:5124, windowHeight: 1019,scrollHeight:571}#
voici le code source 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);
obtenir le contenu de l'iframe hauteur puis de le donner à cette 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);
}
Travailler avec jquery en charge (de la croix-navigateur):
<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);
}
sur redimensionner en responsive page:
$(window).resize(function(){
if($('#containiframe').length !== 0) {
var heightIframe = $('#containiframe').contents().find('body').height();
$('#frame').css("height", heightFrame);
}
});
utilisant 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>
de l'enfant.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>
c'est un peu délicat car vous devez savoir quand la page iframe a chargé, ce qui est difficile quand vous n'êtes pas en contrôle de son contenu. Il est possible d'ajouter un handler onload à l'iframe, mais j'ai essayé cela dans le passé et il a des comportements très différents parmi les navigateurs (ne pas deviner qui est le plus ennuyeux...). Vous devrez probablement ajouter une fonction à la page iframe qui exécute le redimensionnement et injecter du script dans le contenu qui soit écoute pour charger les événements ou redimensionner les événements, qui appelle la fonction précédente. Je pense ajouter une fonction à la page puisque vous voulez vous assurer de sa sécurité, mais je n'ai aucune idée de comment il sera facile à faire.
quelque chose dans ce sens devrait marcher.
parent.document.getElementById(iFrameID).style.height=framedPage.scrollHeight;
chargez ceci avec votre corps chargé sur le contenu iframe.
j'ai une solution facile et vous demande de déterminer la largeur et la hauteur dans le lien, s'il vous plaît essayer (il fonctionne avec la plupart des navigateurs):
<a href='#' onClick=" document.getElementById('myform').src='t2.htm';document.getElementById('myform').width='500px'; document.getElementById('myform').height='400px'; return false">500x400</a>