Skip to content

Instantly share code, notes, and snippets.

@vrusua
Last active October 25, 2021 14:20
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save vrusua/e2440300cdc8ce3cb7e9 to your computer and use it in GitHub Desktop.
Save vrusua/e2440300cdc8ce3cb7e9 to your computer and use it in GitHub Desktop.
Cross domain messaging and dynamic iframe height

Cross domain messaging and dynamic iframe height

CONTENT:

                      ### GENERAL REVIEWS ###

Making Embedded Content Work In Responsive Design

⭐ ⭐ ⭐
by Rachel McCollin | February 27, 2014
img

  • how to make embedded content responsive using CSS
  • look at a solution that uses JavaScript instead of CSS
    doc demo

Cross Domain iframe Resizing

⭐ ⭐
by Chris Coyier | January 5, 2010
doc

XMLHttpRequest: кросс-доменные запросы

⭐ ⭐
doc

                      ### SAME DOMAIN SOLUTIONS ###

Syntax


<iframe id="some_id" name="some_name" src="some_page.html" style="border: 1px solid silver; width:600px" onload="setIframeHeight(this.id)"></iframe>

...

    try {
        var f = document.getElementById("myiframeid");
        // IE opt. for bing/msn needs a bit added or scrollbar appears
        if (f.contentDocument) {
            f.height = f.contentDocument.documentElement.scrollHeight + 30; //FF 3.0.11, Opera 9.63, and Chrome
        } else {
            f.height = f.contentWindow.document.body.scrollHeight + 30; //IE6, IE7 and Chrome
        }
        alert('This iframe should be ' + f.hight + ' pixels in height to avoid scrolling.');
    }

    catch (err) {
        alert('Err: ' + err.message);
        window.status = err.message;
    }

doc doc doc

Setting Iframe Element Height to Iframe Content Height

source

Embed Responsively helps web content producers transform fixed width embedded content into fluid responsive embeds.

service source

jQuery subdonain iframe auto height plugin

  • jQuery plugin to set the height of an iframe to its contents height
    source
  • good for:
    • allowing cross SUBdomain window access
    • you would be allowed to exectue javascript from an iframe sourced on a subdomain on a page sourced on the main domain;
    • will not allow you to change the document.domain to a completely alien domain.
    • works in all relevant browsers

document.domain mod

  • if both documents are on the same top level domain, are using the same protocol and you can add the following line of JavaScript to the page in the iframe:
// on http://sub.site.com
document.domain = "site.com";
// now the subdomain has the same permissions for access

source

                      ### CROSS DOMAIN SOLUTIONS ###
  • overcome cross domain security restrictions
  • needs access to the iframe server to paste code

I. PostMessage
II. JSONP
III. CORS
IV. Window.name
V. Server side proxies
VI. Crazy iFrame Hacks (iFrame INSIDE iFrame trick)

I. PostMessage

  • just pass messages between window objects
  • safe because both pages have to know about it
  • good for:
    • passing events along from one window to the other
    • initializing the state of a new window
    • synchronizing two pages
  • FF 3+, IE 8+, Chrome 1+, Safari 4+

Cross-Domain Messaging With postMessage
doc source demo
Cross Domain IFrame communications throuth PostMessage
doc

// 1) post message syntax
otherWindow.postMessage(message, targetOrigin);

...

// 2) handle the message event in the otherWindow
function receiveMessage(event) {
  if (event.origin !== "http://example.org:8080")
  return;
}

Simple HTML5 PostMessage

source

The iframe page:

<!DOCTYPE html>
<head>
</head>
<body onload="parent.postMessage(document.body.scrollHeight, 'http://target.domain.com');">
  <h3>Got post?</h3>
  <p>Lots of stuff here which will be inside the iframe.</p>
</body>
</html>

The parent page which contains the iframe (and would like to know its height):

<script type="text/javascript">
  function resizeCrossDomainIframe(id, other_domain) {
    var iframe = document.getElementById(id);
    window.addEventListener('message', function(event) {
      if (event.origin !== other_domain) return; // only accept messages from the specified domain
      if (isNaN(event.data)) return; // only accept something which can be parsed as a number
      var height = parseInt(event.data) + 32; // add some extra height to avoid scrollbar
      iframe.height = height + "px";
    }, false);
  }
</script>
<iframe src='http://example.com/page_containing_iframe.html' id="my_iframe" onload="resizeCrossDomainIframe('my_iframe', 'http://example.com');">
</iframe>

cross-domain responsive iframes: automatically set iframe height to fit iframe content

source demo

jQuery iFrame-resizer

  • cross domain sizing iframes to content with support for window resizing
  • uses HTML5 postMessage to keep an iFrame sized to it's content
  • uses MutationObserver to detect changes to the content
    source

jQuery PostMessage & Resize plugins / Cowboy

  • simple and easy window.postMessage communication in browsers that support it (FF3, Safari 4, IE8), while falling back to a document.location.hash communication method for all other browsers (IE6, IE7, Opera)
    doc source doc source

JSChannel / Mozilla

  • small JavaScript abstraction layer on top of HTML5 cross-document messaging
  • builds rich messaging semantics out of window.postMessage()
    doc doc source

Easy XDM library + + +


var socket = new easyXDM.Socket({
  ...,
  onMessage: funciton (message, origin) {
    alert(message);
  }

});

II. JSONP

  • JavaScript Object Notation with Padding (JSONP)
    • a subset of JavaScript with some extra rules
    • non-exutable - just for data
  • good for:
    • data passing
    • RESTful APIs
    • 1-(way/time)-ish cross domain communication
    • hacking - you are adding a script tag to the target domain. They can send anything back, even regular javascript (XSS attack). So you really have to trust them not to do bad stuff or become hacked. Any other webpage can add the same script-tag, and steal the data, so never ever use JSONP for private data.
// 1) create a callback function that accepts some data
function jsonpCallback(data) {
  console.log(data);
}

// 2) include a script with a hint of what your function is called
<script src="http://site.com?cb=jsonpCallback"></script>

// 3) output a script that calls the function and passes in the necessary data
jsonpCallback ({
  "this"  : "is",
  "super" : "awesome",
  "data"  : "forealz"
});

JSONP sending Cross-Domain Messages to an iFrame doc demo

III. CORS

  • Cross-Origin Resource Sharing (CORS) - W3C Working Draft that defines how he browser and server must communicate when accessing sources across origins.
  • CORS sends along an extra header - " Origin: http://site.com "
  • IE 8+, FF 3.5+, Safari 4+, Chrome
  • good for:
    • not working on 40% of the internet (IE 10+)
    • creaiting an extra http request (usually only once)
    • custom grouping options
    • finer grain control over what's accessible
    • Straight Up. Cross Domain XHR
// syntax
function createCORSRequest (method, url) {
  var xhr = new XMLHttpRequst();
  if ("withCredentials" in xhr){
    xhr.open(method, url, true);
  } else if (typeof XDomainRequest != "undefined") {
    xhr = new XDomainRequest();
    xhr.open(method, url);
  } else {
    xhr = null;
  }
  return xhr;
}

// use our new method or lose it

var req = createCORSRequest("get", "http://site.com/");
if (req) {
  req.onload = function() {
    // do something with req.responseText
  };
  req.send();
}

// your server must send back another, saying it's Ok:
// Access-Control-Allow-Origin: http://site.com
// OR
// Access-Control-Allow-Origin: *
// [doc](http://sv-igor.com/ru/htaccess/82-x-frame-options.html)

<?php
  header('X-Frame-Options: GOFORIT');
  header('Access-Control-Allow-Origin: http://site.com');
  header('Access-Control-Allow-Credentials: true');
?>

// * wont work in FF w/ Allow-Credentials
//if you dont need Allow-Credentials, * seems to work
header('Access-Control-Allow-Origin: http://www.example.com');
//if you need cookies or login etc
header('Access-Control-Allow-Credentials: true');
if ($this->getRequestMethod() == 'OPTIONS')
{
  header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
  header('Access-Control-Max-Age: 604800');
  //if you need special headers
  header('Access-Control-Allow-Headers: x-requested-with');
  exit(0);
}

doc

IV. Window.name

  • Superhacky but safer than JSONP
  • works everywhere relevant
// in the child window
window.name = '{"secret": "message"}';
// in the parent window
var secret = JSON.parse(childWindow.name);

V. Server side proxies

  • pretty simple concept, only slightly more difficult to implement
    doc

VI. Crazy iFrame Hacks (iFrame INSIDE iFrame trick)

  • a window can read and write properties of an iframe if it's on the same domain - EVEN IF it's inside of another iframe that isn't on the same domain!
  • a browser hack which allows us to skirt the same origin policy - there is always a chance that it will stop working one day with a browser update (this is still a hack).
  • good for:
    • works at varying levels of success via some slightly different methods in all relevant browsers
    • unfortunately often a best choice for something that works everywhere
www.foo.com/home.html, which iframes
 |-> www.bar.net/framed.html, which iframes
     |-> www.foo.com/helper.html

Communication options for each page: framed.html can send messages to helper.html (iframed) but not home.html (child can't communicate cross-domain with parent).

The key here is that helper.html can receive messages from framed.html, and can also communicate with home.html.

So essentially, when framed.html loads, it works out its own height, tells helper.html, which passes the message on to home.html, which can then resize the iframe in which framed.html sits.

The simplest way to pass messages from framed.html to helper.html is through a URL argument. To do this, framed.html has an iframe with src='' specified. When its onload fires, it evaluates its own height, and sets the src of the iframe at this point to helper.html?height=N

So HOWTO if bar.net wants to talk to foo.com

  • change the url hash on the innermost iframe to the message foo.com/#secret
  • have the top level frame read the message on the hash
  • poll for hashchange the entrie time
  • set up iframes to destroy themselves after each message and just wait for the load event
  • resize the iframe on change, them attach an event handler on the resize event that checks for new data

doc

working example (PHP, cookies)

  • place another iframe page at other domain that belongs to your server which saving height to cookies. Then with an interval read cookies when it is updated, update the height of the iframe.
    source
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment