views:

4125

answers:

3

One of the most difficult problems in my javascript experience has been the correct (that is "cross-browser") computing of a iframe height. In my applications I have a lot of dinamically generated iframe and I want that all do a sort of autoresize at the end of load event to adjust their height and width.

In the case of height computing my best solution is the following (with the help of jquery):

function getDocumentHeight(doc) {
  var mdoc = doc || document;
  if (mdoc.compatMode=='CSS1Compat') {    
      return mdoc.body.offsetHeight;
  }
  else {
    if ($.browser.msie)
      return mdoc.body.scrollHeight;
    else  
      return Math.max($(mdoc).height(), $(mdoc.body).height());
  }
}

I searched in the internet without success. I also tested Yahoo library that have some methods for document and viewport dimensions, but it's not satisfactory. My solution works decently, but sometimes it calculates a taller height. I've studied and tested tons of property regarding document height in Firefox/IE/Safari: documentElement.clientHeight, documentElement.offsetHeight, documentElement.scrollHeight, body.offsetHeight, body.scrollHeight, ... Also jquery doesn't have a coherent behavior in various browser with the calls $(document.body).height(), $('html', doc).height(), $(window).height()

I call the above function not only at the end of load event, but also in the case of dynamically inserted DOM elements or elements hidden or showed. This is a case that sometimes breaks the code that works only in the load event.

There is someone on earth that have a real cross-browser (at least Firefox/IE/Safari) solution? Some tips or hints?

+3  A: 

Although I like your solution, I've always found IFRAMEs to be more trouble than they're worth.

Why ? 1. The sizing issue. 2. the iframe has that src attribute to worry about. i.e. absolute path. 3. the extra complexity with the pages.

My solution - DIVs which are dynamically loaded through AJAX calls. DIVs will auto size. Although the AJAX code requires javascript work (which can be done through frameworks) they are relative to where the site is. 3 is a wash, you're trading complexity in pages up to javascript.

Instead of <IFRAME ...> use <DIV id="mystuff" />

Do the ajax call to fill the mystuff div with data and let the browser worry about it.

jim
I've considered DIV possibility but I don't know an easy solution for the ID (of DOM elements) problem: sharing the same namespace, DIVs has probably many id clashes. Consider that I have many iframes opened at the same time. Nevertheless your solution is worth to be careful considered.
Pier Luigi
You can't AJAX-load content from an external site; it's a browser security violation (cross-site scripting). <iframes> are likely the only client-side solution allowing for external content loading.
artur
A: 

Here is a solution that seems to work. Basically, the scrollHeight is the correct value in most cases. However, in IE (specifically 6 and 7), if the content is simply contained in text nodes, the height is not calculated and just defaults to the height set in CSS or on the "height" attribute on the iframe. This was found through trial and error, so take it for what it is worth.

function getDocumentHeight(doc) {
  var mdoc = doc || document; 
  var docHeight = mdoc.body.scrollHeight;

  if ($.browser.msie) {
      // IE 6/7 don't report body height correctly.  
      // Instead, insert a temporary div containing the contents.

      var child = $("<div>" + mdoc.body.innerHTML + "</div>", mdoc);
      $("body", mdoc).prepend(child);
      docHeight = child.height();
      child.remove();
  }

  return docHeight;
}
Brian Grinstead
A: 

I have found this solution to work in ie 6+, ff 3.5+, safari 4+. I am creating and appending an iframe to the document. The following code is executed at the end of jQuery's load event after some other dom manipulation. The timeout is needed for me because of the additional dom manipulation taking place in the load event.

// sizing - slight delay for good scrollheight
setTimeout(function() {
   var intContentHeight = objContentDoc.body.scrollHeight;
   var $wrap = $("#divContentWrapper", objContentFrameDoc);
   var intMaxHeight = getMaxLayeredContentHeight($wrap);
   $this.height(intContentHeight > intMaxHeight ? intMaxHeight : intContentHeight);

   // animate
   fireLayeredContentAnimation($wrap);
}, 100);

I have some sizing constraints to consider, which is what the getMaxLayeredContentHeight call is checking for me. Hope that helps.

happytime harry