The problem is that browsers use the width of the iframe container to determine how to scale the contents of this frame for printing. Therefore, frames must explicitly define the width.
Unfortunately, dynamically determining print widths is quite complicated and involves hackers. You might be better off just styling the fixed width of the component pages and hard-coded the width of the iframe.
However, if you really need to dynamically size them, you can run the following code after loading the document (tested in Chrome):
var iframes = document.getElementsByTagName("iframe"); for(var i = 0; i < iframes.length; ++i) { var curFrame = iframes[i]; var curBody = curFrame.contentDocument.body; curBody.innerHTML = '<div id="iframe-print-content" style="display:inline-block; overflow:hidden; white-space: nowrap;">' + curBody.innerHTML + '</div>'; var printContent = curFrame.contentDocument.getElementById("iframe-print-content"); var curWidth = printContent.offsetWidth + printContent.offsetLeft; iframes[i].style.width=(curWidth + "px"); }
After that, you can print normally or call window.print() or do whatever you want.
Note. This method will not work on ie6 or ie7, since they do not support inline-block . (There are also several other old browsers that are also not). You can, of course, try
display:-moz-inline-stack; display:inline-block; zoom:1; *display:inline; overflow:hidden; white-space: nowrap;
which will probably take care of most of these cases, but I don't do promises for older browsers.
Good luck, sorry you are stuck with the code on these pages.
Edit: The above solution is a bit inconvenient in Firefox.
Solution for Firefox (tested and works in Firefox 5):
var iframes = document.getElementsByTagName("iframe"); for(var i = 0; i < iframes.length; ++i) { var curFrame = iframes[i]; var curBody = curFrame.contentDocument.body; var oldHTML = curBody.innerHTML; curBody.innerHTML = '<div id="iframe-print-content" style="display:inline-block; overflow:hidden;">' + oldHTML + '</div>'; var printContent = curFrame.contentDocument.getElementById("iframe-print-content"); var curWidth = printContent.offsetWidth + printContent.offsetLeft + 25; var curHeight = printContent.offsetHeight + printContent.offsetTop + 25; curBody.innerHTML = oldHTML; iframes[i].style.width=(curWidth + "px"); iframes[i].style.height=(curHeight + "px"); }
For a full explanation of why this general approach works, see my answer above.
What is the difference from the above solution and why?
Firstly, Firefox features:
There are several key differences. The first notices that Firefox handles display: inline-block and white-space: nowrap differently than Chromium / WebKit for fixed-width elements (so one document looked really unstable with the previous code). It should be further noted that Firefox likes to give a little margin inside its frames. I am not very familiar with the Firefox code that does this (spend my days on Chrome), but my usual solution (besides avoiding frames) is to simply give an extra 25 pixels in the margins. A small amount like this seems like a popular pen to solve this problem.
Now the parts of the code that are actually better:
Firstly, it now stores the old body, raises the body on a div to measure, and then restores the old body. This should avoid problems with inflexible CSS and should guarantee more predictable behavior. Secondly, now it does the same for height as width (my previous assumption that hardcoded widths just worked would not be good, and in any case this is a more flexible solution).
Why is it still bad?
By removing white-space: nowrap , you will get text printing in Chromium / WebKit. It still prints fine, but this is not entirely correct, as some additional texts will be wrapped. To make this a truly workable solution, you still have to execute the browser discovery code.
Again, I recommend using this code to quickly determine the appropriate widths and heights, and then check and adjust the correct sizes for each browser. This is an ugly solution, but ultimately it is the only truly reliable solution.