Resize iframe based on content

March 17, 2010 by: admin

One thing that many are using easyXDM (and other cross-domain hacks) for, is to dynamically change the size of embedded iframes based on the contents size, so as to avoid the scrollbars.

With easyXDM this is really easy:

Instead of embedding the iframe using plain HTML like ..

<iframe src="http://......."></iframe>

.. you do it using easyXDM ..

<br /><!-- use css to style this and its contained iframe --><br /><div id="container">/div><br />
new easyXDM.Socket({
    remote: "http://provider.easyxdm.net/example/resized_iframe.html",
    container: document.getElementById("container"),
    onMessage: function(message, origin){
        this.container.getElementsByTagName("iframe")[0].style.height = message + "px";
    }
});

.. and then in the document to embed, after the content, you put

var socket = new easyXDM.Socket({
    onReady:  function(){
        socket.postMessage(document.body.scrollHeight)
   }
});

You can see at demo of this in action here.

If you plan on navigating the inner window, be aware that this will break the connection and subsequent pages won’t cause the iframe to resize. Therefor the example uses an intermediary frame to facilitate this.

  • Ryan A

    I found you can also get the context by doing something like…

    window.parent.parent.$(“iframe”).css(“height”, obj.value + “px”)

    I also found that I could not get this to work unless I added the remote param on both sides. Whichever side didnt have it would throw an error.

    • http://kinsey.no/ Øyvind Sean Kinsey

      Then you are doing something wrong ;)

      Øyvind Sean Kinsey
      San Francisco, CA

  • Glennnall

    was able to make this work nicely across domains with the test pages, and with other straight html pages, but can’t make it resize when i call a WordPress index.php file – PLEASE someone explain why…???

  • Glennnall

    well it doesn’t like WordPress, i can attest to that. i’ve found NO reason it won’t resize, and i’ve copied everything necessary from the test files to the appropriate WP files. this can leave a bitter taste, don’t ya know!!!

  • novanewsbg

    it works only for subdomains. That’s useless! There are easier ways to solve this for subdomains 

    • http://kinsey.no/ Øyvind Sean Kinsey

      Actually it works across domains, not only across subdomains (no specific support for this actually)

  • electromel

    Great script, work fine on FF, chrome, ie9 and beyond but on ie8 (used with iframe_intermediate.html) the iframe.onload doesn’t seem to get fired. Then there is no postMessage…
    Any idea?

    • electromel

      forgot to say, I’m working on cross domain

    • electromel

      Finally I find a solution
      Here is an update of the script part of resize_intermediate.htm working win ie6 et beyond

                      var iframe;        var timer;        var socket;        function SendSizeInfo() {        var d = iframe.contentWindow.document;        var originalHeight = d.body.clientHeight || d.body.offsetHeight || d.body.scrollHeight;        // We want to monitor the document for resize events in case of the use of accordions and such,        // but unfortunately only the window node emits the resize event, and we need the body’s.        // The only solution then is to use polling..        // Lets start the polling if not all ready started        if (!timer) {        timer = setInterval(function () {        try {        var d = iframe.contentWindow.document;        var newHeight = d.body.clientHeight || d.body.offsetHeight || d.body.scrollHeight;        if (newHeight != originalHeight) {        // The height has changed since last we checked        originalHeight = newHeight;        socket.postMessage(originalHeight);        }        } catch (e) {        // We tried to read the property at some point when it wasn’t available        }        }, 300);        }        // Send the first message        socket.postMessage(originalHeight);        };        //var iframe;        socket = new easyXDM.Socket({        swf: “./easyxdm.swf”,        onReady: function () {        iframe = document.createElement(“iframe”);        iframe.frameBorder = 0;        iframe.style.width = “100%”;        iframe.style.height = “100%”;        document.body.appendChild(iframe);        iframe.src = easyXDM.query.url;        //var timer;        if (iframe.addEventListener)        iframe.addEventListener(“load”, SendSizeInfo, false)        else if (iframe.attachEvent)        iframe.attachEvent(“onload”, SendSizeInfo)        else if (document.getElementById)        iframe.onload = SendSizeInfo        },        onMessage: function (url, origin) {        iframe.src = url;        }        });       

      • Cedlemlaro

        Dear Electromel, thank you so much I have been trying to fix it for more than 3 month!!! I cant believe, it is now working on IE8!

        Could you please add me on Skype (my username is cedlemlaro), I would really like to know why it was not working.

  • Scotty Fitz

    Hey Oyvind !

    Great library, but please, please – can you have a quick look at this and see what you think ?
    I  give my iFrame code to clients, so they can display the dynamic content from my site. I’d like the iFrame that lives on their page to resize to fit my content.
    I followed the instructions above, but maybe I am missing something?

    I don’t get any errors, but the iFrame stays the default height (150px).

    The code I give my client site is :

       
       
            var transport = new easyXDM.Socket({
                remote: “http://www.lipsum.com/”,
                container: “container”,
                onMessage: function (message, origin) {
                    this.container.getElementsByTagName(“iframe”)[0].style.height = message + “px”;
                }
            });
       
    ________________________________________________________________________________________________

    This is the code that goes on the document I want to embed :

        var socket = new easyXDM.Socket({    onReady: function () { socket.postMessage(document.body.scrollHeight) }            });

    I’m hoping there is something simple I’m doing wrong…
    Can you PLEASE help Oyvind ?

    Thanks a lot.

  • aendrew

    I was able to get this working by putting the socket code in my theme’s footer template, and was pleasantly surprised that clicking iframe’d links resulted in those also changing the window’s height — without having created any sort of intermediary page. Is there any reason why this shouldn’t work that I should be aware of? Or am I just misunderstanding the concept of intermediary frames in this context?

  • Ajeftink

    So I have the code working but have two bugs…1. When the Iframe is loaded it sets to width to 300px.  I’ve added code to change the width afterwards but why is it setting the width to 300px?  Is there something in your code doing that or is that problem on my end?

    2.  Navigating to a different page on the same domain and then returning to the page with with the iframe results in the iframe height being almost twice as much as it should be.  I don’t know why this is happening.

  • Shae Strachan

    How can I override the iFrame’s content css? I’d simply like to be able to override the body background color.

  • clh

    I don’t get this. I put in the code and all I get is a blank page no matter what I try.

  • brianlmerritt

    For people struggling with the default width, on your “master” page add the following below the onMessage:

    this.container.getElementsByTagName(“iframe”)[0].style.width = “800px”;

  • brianlmerritt

    From the comments a lot of people (including developers) struggle getting this together.

    1. If you are using easyXDM.debug.js then you need to include the other .js files that come on the github /src and /src/stack folders – and this needs to be installed at both ends

    2. the code in the example (resize*.html) files is different from the code listed above. Both work, but you have to make sure the .js and .swf files are in the right locations or edit the html files.

    3. resize_intermediate.html needs to be located on the remote (embed) web domain. If the master location doesn’t reference this, it will not work.

    4. Most (All?) of the issues with cross domain have nothing to do with easyXDM. The setup is wrong, the files are missing or located wrong, etc.

    5. If you are struggling, start with running the full example package in just one domain. Once THAT is working, do the same in the other domain. Once both ends are working, getting each end to do it’s part is soooooo much easier.

    6. If you miss this because DISQUS defaults to “best” comment, it’s not my fault. Put a reply under this and eventually it will bubble up and help someone else.

    7. You can find me on twitter @brianlmerritt, should you want to :)

    • brianlmerritt

      ps – This works fine with WordPress and Moodle. It is probably theme dependant, but both appear to work well with twitter bootstrap based themes. Am just going to test now with video and see how that gets on…

  • Tobias

    Thanks for this solution, it works great.

    A couple of things I noticed in case they trip anyone else up:
    1. The css styling on the remote page is important. You need “overflow: hidden” to make sure the iframe doesn’t show a scroll-bar, and you need “margin: 0px” and “padding: 0px” if you want the paragraph left margin to line up between the local and the remote text. All this is included in the demo files but I didn’t realise it was important until I removed it.

    2. If you want the iframe to take up the full width of the local page then add the line “this.container.getElementsByTagName(“iframe”)[0].style.width = “100%”;” just after the line “this.container.getElementsByTagName(“iframe”)[0].style.height = message + “px”;” in the javascript on the local page.