87

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

http://maxq.tigris.org/


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.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Piotr Kula
  • 9,597
  • 8
  • 59
  • 85
  • 4
    the easyXDM example actually has a lot less code, does not rely on external libs, and also work in older browsers :) And yes, I'm biased since I'm the author, but still.. – Sean Kinsey May 10 '11 at 21:13
  • I tried easyXDM but i could not get internal frame browsing to other links to work.. i looked for examples.. there were links that are broke and the example page was not to clear.. It did work! and was my original answer.. but I used this. Can you post a way for internal browsing please.. i looked and looked.. – Piotr Kula May 11 '11 at 05:18
  • @ppumkin the [example that ships](http://consumer.easyxdm.net/current/example/resize_iframe.html) with the download fully supports internal browsing. The broken link is probably to an experiment I did, but the server got flushed at one point.. – Sean Kinsey May 11 '11 at 07:21
  • 1
    Yea looked at that- and looked and looked :D for some reason I could not get it work with my site. I will try again. – Piotr Kula May 11 '11 at 10:21
  • 1
    It works- but if i click a link on that domain it reloads the page- with you library- but i cannot get any message. How can i make it accept requests regardless of where they comming from. And what is this easyxdm.swf for? :) – Piotr Kula May 11 '11 at 10:49
  • I tried the intermediate iframe solution- all i get in the intermediate iframe the whole time is url is undefined or empty. i put ?url=my_page.html / ?http://domain.com/my_page.html / i included the name.html and swf... it wont load throuhg the intermediate frame? – Piotr Kula May 11 '11 at 11:32
  • Ok- well running the site localhost and calling external domains.. does not work.?! :( I got it working eventually on the separate domains. I hope its better than the other solution... – Piotr Kula May 11 '11 at 12:50
  • Yea yours is much better.. but it does not work in IE7 – Piotr Kula May 11 '11 at 13:04
  • @ppumking Sure about that? The examples work as expected. It's up to you to adapt them. They also work in IE6/IE7 (just tested) (only set up properly for Flash as fallback), and should work equally in IE7. Also, none of my 'big' users has reported anything else ;) – Sean Kinsey May 11 '11 at 20:33
  • Yea its amazing! Thanks- but why am i struggling so much to change the width? Content grows but does not shrink. I use scrollWidth - if i navigate to smaller page the scrollWidth stays the same and the clientWidth,clientWidth.. its driving me crazy. I try to reset the width to a samll one and then apply to recieved width.. i supposuse the inetermediate frame needs something adding to it.. – Piotr Kula May 11 '11 at 20:44
  • @ppumking that's because block elements always flow to the available width unless you say otherwise. The height is a product of the width + content, not the other way around. – Sean Kinsey May 12 '11 at 07:13
  • I rolled back your last edit because the answer doesn't belong in the question. On this site, [we maintain a strict separation between questions and answers](/tour). If you've found the solution to your own problem, that's great! Please [answer your own question](/help/self-answer) in the space for an answer below. – Stephen Ostermiller Jun 22 '22 at 10:45
  • Stephen . No problem my friend.. Thank you for sorting this question 11 years after I asked it.. to be fair the rules and SO were not the same back then.. IMHO - I liked it more then but never the less.. Thank you for clearing it up and enjoy your new job – Piotr Kula Jun 22 '22 at 12:15

9 Answers9

29

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

Baker Humadi
  • 291
  • 3
  • 3
  • This works great but not quite as much in IE. I had to send 2 variables, but IE won't accept "data" if its an array or object. However, I simply created data as data = var1 + "|" var2. On the parent, you just split the string on | and get your 2 vars back. – dbonneville May 07 '13 at 00:33
10

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..

Sean Kinsey
  • 37,689
  • 7
  • 52
  • 71
  • On the contrary my friend. I found a way to resize the iframe from a cross doimain page to the iframes docuemnt size and no scrolbars. its kinda hacky but will post later.. its just so simple its unbelievable. – Piotr Kula May 06 '11 at 15:41
  • yea... I used sendmessage jquwery plugin- i though i found another hack- false positive.. ;) thanks for the good tip! – Piotr Kula May 10 '11 at 08:04
  • Well, sometimes the best thing is to listen to your peers - the odds for you discovering some magic hack that no-one else has is pretty slim :) – Sean Kinsey May 10 '11 at 14:02
  • Imagine if i did- by pure hit and miss - would be fantastic. But yea- slim :D Thanks – Piotr Kula May 10 '11 at 14:11
  • True - if nothing else, you have at least tried, experimented, and perhaps learned something new as well :) – Sean Kinsey May 10 '11 at 21:10
  • @SeanKinsey Which browsers supports the onResize ( for iframe ) ? – Royi Namir Oct 05 '13 at 07:23
  • @RoyiNamir none, unless you consider seamless iframes - http://benvinegar.github.io/seamless-talk/#/ The easyXDM example uses Cross-Domain Messaging to relay regular resize events. – Sean Kinsey Oct 07 '13 at 21:37
  • @SeanKinsey I meant -- A Page set a new hash value to its iframe and now it needs to resize the iframe in order to raise the onresize event ( at the iframe side). are you telling me that the event won't fire at the iframe size ? ( that's my question was about). thanks for reply. [I even asked a new question about it](http://stackoverflow.com/questions/19195363/iframe-cross-domain-communication-resize-event-cross-browser) – Royi Namir Oct 08 '13 at 04:52
5

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
        );
    }
});
David Bradshaw
  • 11,859
  • 3
  • 41
  • 70
0

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

0

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.

sparkholiday
  • 82
  • 10
0

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

Test Work Screenshot

Limitless isa
  • 3,689
  • 36
  • 28
0

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...

T.Rob
  • 31,522
  • 9
  • 59
  • 103
  • 2
    Off course, the "iframe" scroll will be, allways, of the same size of the page. So, while navigating, You just see it as it was the "page" scroll. – Elton Morais Dec 03 '11 at 03:26
-2

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.

  • I don't think you are addressing the actual question asked. – Andrew Barber Jan 10 '14 at 00:31
  • Yea- This is pure javascript to resize an iframe on the same domain. It is much easier to use jQuery any way. This wont work cross site and there is nothing fancy in here that will allow it. And there is no such thing as php scripting?! – Piotr Kula Jan 10 '14 at 10:44
-2

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.

anothershrubery
  • 20,461
  • 14
  • 53
  • 98
  • Yes i tried that already. It works great.. on the same domain like you said.. Tell me- how does a browser know how much 100% is when it initially calculates the height? why cant we access those values also? Chrome stores this in computed styles for every single page in the iframe even x-domain... – Piotr Kula May 06 '11 at 08:34
  • Height gets calculated depending on the contents and the attributes they have. The height of an element is uncertain until the the children are rendered. – MarioRicalde May 06 '11 at 09:28
  • how can i get the rendered values then? like the inspect in chrome does? – Piotr Kula May 06 '11 at 13:16
  • -1 since this doesn't work cross-domain, which is what he asked for. – Sean Kinsey May 06 '11 at 15:07
  • You can't get the values. The inspector can because it has "browser extension" level permissions and not "web page with a different origin" level permissions. – Quentin May 06 '11 at 15:11