1

I'm attempting to send the height of my page from an iframe to the parent page using the postMessage API. The idea is that when the total page height of the iframed page changes, it will send that height to the parent. The parent will then adjust the iframe's height to match. I currently have this working great in the latest Google Chrome.

Unfortunately, I've run into a hiccup with IE9/10/11 and Firefox. Once the .scrollHeight has been set to its largest, it stays there. Attempting to send a smaller height just sends the previously highest height, even though the originating page's height is considerably less.

I've figured that it's probably because the iframe the page is being held in is affecting the originating page's height. So this may actually have a CSS related solution?

Here is a reduced test case I put together. This parent page contains an iframe that holds a page that can increase and decrease its own height using two buttons I added. Additionally, a third button grabs the pages height and sends it to the parent using the postMessage API.

Example Page: http://iaviglobal.com/parent.html

I've made it so that the height that is sent and received is logged in the console. Test the functionality by adding the orange block and sending the document height. Then hide the orange block and send the height again. Works great in the latest Chrome, not so much in IE and FF.

Any help would be greatly appreciated.

EDIT: I've determined that I can avoid this issue if I use the height of any element other than <html> and <body>. For instance, reporting the height of <div id="main"> will give an accurate number regardless of browser. <html> and <body> seem to report the full iframe height in IE and Firefox even if the content inside them don't fill that much space.

However, it would still be preferred if I could get the accurate <html> or <body> height instead of using a <div>.

jkupczak
  • 2,891
  • 8
  • 33
  • 55

3 Answers3

2

Interestingly, this behaviour is perhaps the "correct" behaviour.

The scrollHeight attribute must return the result of running these steps:

  1. Let viewport height be the height of the viewport excluding the height of the scroll bar, if any, or zero if there is no viewport.
  2. If the element is the root element and the Document is not in quirks mode return max(viewport scrolling area height, viewport height).
  3. If the element is the HTML body element, the Document is in quirks mode and the element has no associated scrolling box, return max(viewport scrolling area height, viewport height).
  4. If the element does not have any associated CSS layout box return zero and terminate these steps. 5.Return the height of the element's scrolling area.

reference: http://dev.w3.org/csswg/cssom-view/#dom-element-scrollheight

According to this (somewhat old) comparison body.clientHeight and body.offsetHeight seems to give the values you want in standards mode.

mfirdaus
  • 4,574
  • 1
  • 25
  • 26
  • Thank you for the reply. I can confirm that `body.clientHeight` and `body.offsetHeight` both return accurate numbers in standards mode. The funny thing is that I just figured out that .scrollHeight works in IE/FF too if I reference the `` tag. It's just the `` tag that's not working as you'd expect. `.clientHeight`, `.offsetHeight`, and `.scrollHeight` all act funny exclusively on the `` tag in IE/FF. Chrome doesn't care if I use the `` tag to grab the height, it works just the same as every other tag. – jkupczak May 27 '14 at 20:24
1

I tested this in IE11 and Firefox 29. It works perfectly when I moved the class="global-embed" from the head-element to the body-element inside the iFrame!

<html id="global-embed" lang="en">
<body class="global-embed">
Mystic
  • 25
  • 4
1

I believe IE/FF are giving you the correct behavior, as explicitly setting an element height to a value greater than the content height makes the scroll height equal to that value example.

You should be using offsetHeight instead:

function postit() {
  parent.postMessage(document.getElementsByClassName("global-embed")[0].offsetHeight,"http://iaviglobal.com");
  console.log("iframe sent this height: " + document.getElementsByClassName("global-embed")[0].offsetHeight);
};

Here is a working copy of your example.

Update

Looks like in IE9/10 html element inherits the iframe height, but using the body element instead works as expected:

//http://stackoverflow.com/a/17907562/328072
function getInternetExplorerVersion()
{
  var rv = -1;
  if (navigator.appName == 'Microsoft Internet Explorer')
  {
    var ua = navigator.userAgent;
    var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
    if (re.exec(ua) != null)
      rv = parseFloat( RegExp.$1 );
  }
  else if (navigator.appName == 'Netscape')
  {
    var ua = navigator.userAgent;
    var re  = new RegExp("Trident/.*rv:([0-9]{1,}[\.0-9]{0,})");
    if (re.exec(ua) != null)
      rv = parseFloat( RegExp.$1 );
  }
  return rv;
}
function postit() {
  var elm = document.getElementsByClassName("global-embed")[0];
  var ie  = getInternetExplorerVersion();
  var h   = ie == -1 || ie >= 11 ? elm.offsetHeight : document.body.scrollHeight;     
  parent.postMessage(h,"http://iaviglobal.com");
  console.log("iframe sent this height: " + h);
};

Updated working example here.

MK.
  • 5,139
  • 1
  • 22
  • 36
  • Works for me in Firefox and Chrome. But IE9 doesn't work at all. Haven't tested it in IE10 or 11 yet. – jkupczak May 27 '14 at 20:29
  • Thanks for the update. I expected that the `` tag would be inheriting from the ` – jkupczak May 29 '14 at 20:19
  • I'm glad I was able to help, According to my test, IE11 gives the correct height using `html` element `offsetHeight`, thats why I excluded it from falling back to using `document.body.scrollHeight`. In dev tools, select the `html` element and check the computed style but it would give the same result in IE11 too. Its better to make a script logging `offset/scroll height` for both `html` and `body` elements to see how the browser behaves. – MK. May 30 '14 at 11:27