Reputation: 9811
How do I resize an iframe from another domain?
Past few days I have been trying to integrate an iframe into a site. This is a short term solution while the other side develops and API(could take months...) And because this is as short term solution we done want to use easyXDM- I have access to the other domain but its difficult enough asking them to add p3p header as it is.....
3 iframes
The closest solution I found was the 3 iframes- but it goes mental of chrome and safari so I cannot use that.
open in chrome
http://css-tricks.com/examples/iFrameResize/crossdomain.php#frameId=frame-one&height=1179
Measure the scrollbars
I found a another post on how to use the scrollheight to try and resize the form.. in theory it works well but I could not apply it properly using the iframes scroll height..
document.body.scrollHeight
That obvoisly uses the bodies height (cannot access these properties 100% is based on the clients display canvaz and not the x-domains document height)
I tried using jQuery to get the iframes height
$('#frameId').Height()
$('#frameId').clientHeight
$('#frameId').scrollHeight
return values different in chrome and ie - or just don't make sense at all. The problem is that everything inside the frame is denied- even the scrollbar...
Computed Styles
But if I inspect and element in chrome of the iframe it badly shows me the documents dimensions inside the iframe (using jQuery x-domain to get iframe.heigh - access denied) There is nothing in the computed CSS
Now how does chrome calculate that? (edit- browser re-renders the page using its build in rendering engine to calculate all these settings - but are not attached anywhere to prevent cross-domain fraud.. so..)
HTML4
I read specification of HTML4.x and it says there that there should be read-only values exposed via document.element but it's access denied via jQuery
Proxy Frame
I went down the route of proxying the site back and calculating which is OK.. until a user logs in through the iframe and the proxy gets a login page instead of the actual content. Also to some calling the page twice is not acceptable
http://www.codeproject.com/KB/aspnet/asproxy.aspx
http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/
Re-Render the page
I did not go this far but there are jscript engines out there that will look at the source and re-render the page based on the source file. but it would require hacking those jscripts.. and that's not an ideal situation for commercial entities... and some invoke pure Java applets or server side rendering
http://en.wikipedia.org/wiki/Server-side_JavaScript
http://htmlunit.sourceforge.net/ <-java not jscript
All this can do done with HTML5 sockets. But easyXDM is great fallback for non HTML5 complaint pages.
Solution 1 Very Great Solution!
Using easyXDM
On your server you set up a page in the form of
<html>
<head>
<script src="scripts/easyXDM.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">
var transport = new easyXDM.Socket(/** The configuration */{
remote: "http://www.OTHERDOMAIN.example/resize_intermediate.html?url=testpages/resized_iframe_1.html",
//ID of the element to attach the inline frame to
container: "embedded",
onMessage: function (message, origin) {
var settings = message.split(",");
//Use jquery on a masterpage.
//$('iframe').height(settings[0]);
//$('iframe').width(settings[1]);
//The normal solution without jquery if not using any complex pages (default)
this.container.getElementsByTagName("iframe")[0].style.height = settings[0];
this.container.getElementsByTagName("iframe")[0].style.width = settings[1];
}
});
</script>
</head>
<body>
<div id="embedded"></div>
</body>
and on the callers domain they just need to add the intermediate_frame HTML and easyXDM.js
in the same place. Like a parent folder - then you can access relative directories or a contained folder just for you.
Upvotes: 87
Views: 95943
Reputation: 3802
HTTPS another link get height to iframe autoheight
https://-a.com content:
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
</head>
<body>
Test Page:
<hr/>
<iframe id="iframe" src="https://-b.com" style="width:100%;min-height:600px;border:none;" scrolling="no" ></iframe>
<script>
// browser compatibility: get method for event
// addEventListener(FF, Webkit, Opera, IE9+) and attachEvent(IE5-8)
var myEventMethod =
window.addEventListener ? "addEventListener" : "attachEvent";
// create event listener
var myEventListener = window[myEventMethod];
// browser compatibility: attach event uses onmessage
var myEventMessage =
myEventMethod == "attachEvent" ? "onmessage" : "message";
// register callback function on incoming message
myEventListener(myEventMessage, function (e) {
// we will get a string (better browser support) and validate
// if it is an int - set the height of the iframe #my-iframe-id
if (e.data === parseInt(e.data))
document.getElementById('iframe').height = e.data + "px";
}, false);
</script>
</body>
</html>
https://-b.com iframe content:
<!DOCTYPE html>
<html>
<head>
<title>Test Iframe Content</title>
<script type="text/javascript">
// all content including images has been loaded
window.onload = function() {
// post our message to the parent
window.parent.postMessage(
// get height of the content
document.body.scrollHeight
// set target domain
,"*"
)
};
</script>
</head>
<body>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>1
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>2
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>3
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>4
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>5
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>6
</body>
</html>
Work Table:
xcom http > ycom https WORK
xcom https > ycom https WORK
xcom http > ycom http WORK
xcom https > ycom http WORK
Upvotes: 0
Reputation: 82
Have you looked into the 'object-fit' HTML5 attributes? Scales video/images to the iframe, rather than scaling the iframe (nice if you grab a medium-sized image that ends up being 5,000px in width). The "fit" option (others are "cover" and "fill") uses a sort-of-letterbox approach to fit the source in while preserving the aspect ratios. For viewing by the HTML5-less out there, it looks like there a whoooole lot of polyfills available. This one is great, but a bug on Edge's end has kept it incompatible with Microsoft's New Nightmare for about a year, now: https://github.com/anselmh/object-fit
EDIT: To get around cross domain issues, you can always just do the work in a Chrome Extension Content Script, since it thinks it's part of the page you're sticking your iframe on.
Upvotes: 0
Reputation: 474
Nowadays there is only 4 solutions I know:
Only the third one can resolve many problems. For example you can create responsive iFrame; close it from inside or you can communicate with it. But to do that you need iFrame in Iframe and the "third party cookies" workaround (optional).
I've created an article about it with example: Event-driven cross-domain iFrame
Upvotes: 0
Reputation: 13077
Having looked a lots of different solution to this I ended up writing a simple small library to take a account of a number of different use cases. As I needed a solution that supported multiple user generated iFrames on a portal page, supported browser resizes and could cope with the host page JavaScript loading after the iFrame. I also add support for sizing to width and a callback function and allow the override of the body.margin, as you will likely want to have this set to zero.
https://github.com/davidjbradshaw/iframe-resizer
The iframe code is just a little self-contained JavaScript, so that it's a good guest on other people pages.
The script is then initialised on the host page with the following available options.
iFrameResize({
log : true, // For development
autoResize : true, // Trigering resize on events in iFrame
contentWindowBodyMargin: 8, // Set the default browser body margin style (in px)
doHeight : true, // Calculates dynamic height
doWidth : false, // Calculates dynamic width
enablePublicMethods : true, // Enable methods within iframe hosted page
interval : 32, // interval in ms to recalculate body height, 0 to disable refreshing
scrolling : false, // Enable the scrollbars in the iFrame
callback : function(messageData){ // Callback fn when message is received
$('p#callback').html(
'<b>Frame ID:</b> ' + messageData.iframe.id +
' <b>Height:</b> ' + messageData.height +
' <b>Width:</b> ' + messageData.width +
' <b>Event type:</b> ' + messageData.type
);
}
});
Upvotes: 5
Reputation: 1
To resize an iframe, here's a simple script:
this goes in the head: (this was written for a php script, for html, change the ' to " and the \" to '...
<script type='text/javascript'>
<!--
function resizeIframe(id){
/*
this.obj=obj
//this.obj.width=null
//this.obj.width=window.frames[\"sizeframe1\"].document.body.scrollWidth
this.obj.style.height=\"\" // for Firefox and Opera
setTimeout(\"this.obj.style.height=this.obj.contentWindow.document.body.scrollHeight+(notIE?heightOffset:0)\",10) // setTimeout required for Opera
*/
el=document.getElementById(id)
el.style.height='200px' // for Firefox and Opera
setTimeout('el.style.height=el.contentWindow.document.body.scrollHeight+\"px\"',1) // setTimeout required for Opera
}
// -->
</script>"
end of head
this goes in the body (remember, this was written for a php script, for html change all the ' to " and the \" to '...)
<iframe onload='resizeIframe(this.id)' allowTransparency=\"true\" name='ccpaymentwindow' id='sizeframe1' marginwidth='1' marginheight='1' height='700' width='690' border='0' frameborder='1' scrolling='no' src='ccmslink.php?variable1=" . $variable1 . "'></iframe>
bonus: there's some hints above. As it is set for php scripting, you can do a lot with it...to learn more, do more...
the key to this is "sizeframe1" .... for multiple "resizers" on the same page, copy the same script but change the id in iframe and the name in the script in the head, and viola! you have multiple resizers on the same page...it works very well!
have phun.
Upvotes: -2
Reputation: 291
Similar to what Sean has mentioned, you can use postMessage. I've spent so much time trying different ways to resize iframe with cross-domain but no luck until I stumbled on this great blog post by David Walsh: http://davidwalsh.name/window-iframe
This is a combination of my code and David's solution. My solution is geared specifically toward resizing iframes.
In the child page, find the height of the page and pass it to the parent page (which contains the iframe). Replace element_id with your element id (html, body, whatever).
<script>
function adjust_iframe_height(){
var actual_height = document.getElementById('element_id).scrollHeight;
parent.postMessage(actual_height,"*");
//* allows this to post to any parent iframe regardless of domain
}
</script>
<body onload="adjust_iframe_height();">
//call the function above after the content of the child loads
On the parent window, add this code. Replace iframe_id with your iframe ID:
<script>
// Create IE + others compatible event handler
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
// Listen to message from child window
eventer(messageEvent,function(e) {
console.log('parent received message!: ',e.data);
document.getElementById('iframe_id').height = e.data + 'px';
},false);
</script>
If you open the console, you will see the height being printed in the console log. This will help you in debugging which is why I left it there.
Best, Baker
Upvotes: 29
Reputation: 1
Instead of use scroll=no on the iframe, I change it to "auto". Then, I get the size of the actual window
$(window).height();
and use that as the iframe height attribute.
Well, the result is...
We will never have the "page" scroll, only the "iframe" scroll. When You navigate, doesn't matter who is the scroll, but the important is that there's only 1.
Well, there's the problem of the user simply resize the window while he's navigating. To solve that, I use:
setInterval(getDocHeight, 1);
Did You think that that solution will cause any bugs? It's working for me, and on the iFrame I had dynamic contect generated by php. I'm afraid of future bugs with that...
Upvotes: 0
Reputation: 38046
The thing is - there is no other way than using Cross-Domain Messaging for this since you need to get the computed height from a document in one domain, to a document in a different domain.
So, either you do this using postMessage
(works in all moder browsers), or you spend 5 minutes adapting the resize iframe example from easyXDM.
The other party really just needs to copy a few files onto their domain, and add a single line of code to their document..
Upvotes: 10
Reputation: 20993
Are you looking to find the height of the page contained within the iframe? I got some javascript working which checks the height of the iframe content then sets the iframe's height to the height of the content.
var Height = document.getElementById('iFrameId').contentWindow.document.body.scrollHeight;
document.getElementById('iFrameId').height = Height;
However, this only works if the page you are showing in the iframe is on the same domain. If it's not you cannot access the required information. Hence, the access denied error.
Upvotes: -2