iFrame Resizer
This library enables the automatic resizing of the height and width of both same and cross domain iFrames to fit the contained content. It provides a range of features to address the most common issues with using iFrames, these include:
- Height and width resizing of the iFrame to content size.
- Works with multiple and nested iFrames.
- Automatic domain authentication for cross domain iFrames.
- Provides a range of page size calculation methods to support complex CSS layouts.
- Detects changes to the DOM that can cause the page to resize using MutationObserver.
- Detects events that can cause the page to resize (Window Resize, CSS Animation and Transition, Device Orientation and Mouse events).
- Simplified messaging from iFrame to host page via postMessage.
- Fixes in page links in iFrame and supports links from the iFrame to the parent page.
- Provides custom sizing and scrolling methods.
- Works with ViewerJS to support PDF and ODF documents.
- Fallback support down to IE8.
Getting started
The package contains two minified JavaScript files in the js folder. The first (iframeResizer.min.js) is for the page hosting the iFrames. It can be called with native JavaScript;
1 |
iFrameResize( [{options}], [css selector] || [iframe] ); |
or via jQuery. (See notes below for using native version with IE8).
1 |
$('iframe').iFrameResize( [{options}] ); |
The second file (iframeResizer.contentWindow.min.js) is a native JavaScript file that needs placing in the page contained within your iFrame. This file is designed to be a guest on someone else’s system, so has no dependencies and won’t do anything until it’s activated by a message from the containing page.
Typical setup
The normal configuration is to have the iFrame resize when the browser window changes size or the content of the iFrame changes. To set this up you need to configure one of the dimensions of the iFrame to a percentage and tell the library only to update the other dimension. Normally you would set the width to 100% and have the height scale to fit the content.
1 2 |
<iframe src="http://anotherdomain.com/iframe.html" width="100%" scrolling="no"></iframe> <script>iFrameResize({log:true})</script> |
Note that scrolling is set to ‘no’, as older versions of IE don’t allow this to be turned off in code and can just slightly add a bit of extra space to the bottom of the content that it doesn’t report when it returns the height. If you have problems, check the troubleshooting section below.
Example
To see this working take a look at this example and watch the console.
Options
log
1 2 |
default: false type: boolean |
Setting the log
option to true will make the scripts in both the host page and the iFrame output everything they do to the JavaScript console so you can see the communication between the two scripts.
autoResize
1 2 3 |
default: true type: boolean |
When enabled changes to the Window size or the DOM will cause the iFrame to resize to the new content size. Disable if using size method with custom dimensions.
Note: When set to false the iFrame will still inititally size to the contained content, only additional resizing events are disabled.
bodyBackground
1 2 3 |
default: null type: string |
Override the body background style in the iFrame.
bodyMargin
1 2 3 |
default: null type: string || number |
Override the default body margin style in the iFrame. A string can be any valid value for the CSS margin attribute, for example ‘8px 3em’. A number value is converted into px.
checkOrigin
1 2 3 |
default: true type: boolean || array |
When set to true, only allow incoming messages from the domain listed in the src
property of the iFrame tag. If your iFrame navigates between different domains, ports or protocols; then you will need to provide an array of domains or disable this option.
enableInPageLinks
1 2 3 |
default: false type: boolean |
When enabled in page linking inside the iFrame and from the iFrame to the parent page will be enabled.
enablePublicMethods
1 2 3 |
default: false type: boolean |
If enabled, a window.parentIFrame
object is created in the iFrame that contains methods outlinedbelow.
interval
1 2 3 |
default: 32 (in ms) type: number |
In browsers that don’t support mutationObserver, such as IE10, the library falls back to using setInterval, to check for changes to the page size. The default value is equal to two frame refreshes at 60Hz, setting this to a higher value will make screen redraws noticeable to the user.
Setting this property to a negative number will force the interval check to run instead ofmutationObserver.
Set to zero to disable.
heightCalculationMethod
1 2 3 |
default: 'bodyOffset' values: 'bodyOffset' | 'bodyScroll' | 'documentElementOffset' | 'documentElementScroll' | 'max' | 'min' | 'grow' | 'lowestElement' |
By default the height of the iFrame is calculated by converting the margin of the body
to px and then adding the top and bottom figures to the offsetHeight of the body
tag.
In cases where CSS styles causes the content to flow outside the body
you may need to change this setting to one of the following options. Each can give different values depending on how CSS is used in the page and each has varying side-effects. You will need to experiment to see which is best for any particular circumstance.
- bodyScroll uses
document.body.scrollHeight
* - documentElementOffset uses
document.documentElement.offsetHeight
- documentElementScroll uses
document.documentElement.scrollHeight
* - max takes the largest value of the main four options *
- min takes the smallest value of the main four options *
- grow same as max but disables the double resize that is used to workout if the iFrame needs to shrink. This provides much better performance if your iFrame will only ever increase in size
- lowestElement Loops though every element in the the DOM and finds the lowest bottom point †
Notes:
If the default option doesn’t work then the best solution is often to use lowestElement in modern browsers and max in IE10 downwards.
1 2 3 4 5 |
var isOldIE = (navigator.userAgent.indexOf("MSIE") !== -1); // Detect IE10 and below iFrameResize( { heightCalculationMethod: isOldIE ? 'max' : 'lowestElement' }); |
† The lowestElement option is the most reliable way of determining the page height. However, it does have a performance impact in older versions of IE. In one screen refresh (16ms) Chrome can calculate the position of around 10,000 html nodes, whereas IE 8 can calculate approximately 50. It is recommend to fallback to max or grow in IE10 and below.
* The bodyScroll, documentElementScroll, max and min options can cause screen flicker and will prevent the interval trigger downsizing the iFrame when the content shrinks. This is mainly an issue in IE 10 and below, where the mutationObserver event is not supported. To overcome this you need to manually trigger a page resize by calling the parentIFrame.size() method when you remove content from the page.
maxHeight / maxWidth
1 2 3 |
default: infinity type: integer |
Set maximum height/width of iFrame.
minHeight / minWidth
1 2 3 |
default: 0 type: integer |
Set minimum height/width of iFrame.
resizeFrom
1 2 3 |
default: 'parent' values: 'parent', 'iframe' |
Listen for resize events from the parent page, or the iFrame. Select the ‘iframe’ value if the iFrame can be resized independently of the browser window. Selecting this value can cause issues with some height calculation methods on mobile devices.
scrolling
1 2 3 |
default: false type: boolean |
Enable scroll bars in iFrame.
sizeHeight
1 2 3 |
default: true type: boolean |
Resize iFrame to content height.
sizeWidth
1 2 3 |
default: false type: boolean |
Resize iFrame to content width.
tolerance
1 2 3 |
default: 0 type: integer |
Set the number of pixels the iFrame content size has to change by, before triggering resize of the iFrame.
Callback Methods
closedCallback
1 2 |
type: function (iframeID) |
Called when iFrame is closed via parentIFrame.close()
method.
initCallback
1 2 |
type: function (iframe) |
Initial setup callback function.
messageCallback
1 2 |
type: function ({iframe,message}) |
Receive message posted from iFrame with the parentIFrame.sendMessage()
method.
resizedCallback
1 2 |
type: function ({iframe,height,width,type}) |
Function called after iFrame resized. Passes in messageData object containing the iFrame, height,width and the type of event that triggered the iFrame to resize.
scrollCallback
1 2 |
type: function ({x,y}) |
Called before the page is repositioned after a request from the iFrame, due to either an in page link, or a direct request from either parentIFrame.scrollTo() or parentIFrame.scrollToOffset(). If this callback function returns false, it will stop the library from repositioning the page, so that you can implement your own animated page scrolling instead.
IFrame Methods
To enable these methods you must set enablePublicMethods to true. This creates thewindow.parentIFrame
object in the iFrame. These method should be contained by a test for thewindow.parentIFrame
object, in case the page is not loaded inside an iFrame. For example:
1 2 3 |
if ('parentIFrame' in window) { parentIFrame.close(); } |
close()
Remove the iFrame from the parent page.
getId()
Returns the ID of the iFrame that the page is contained in.
scrollTo(x,y)
Scroll the parent page to the coordinates x and y.
scrollToOffset(x,y)
Scroll the parent page to the coordinates x and y relative to the position of the iFrame.
sendMessage(message,[targetOrigin])
Send data to the containing page, message
can be any data type that can be serialized into JSON. ThetargetOrigin
option is used to restrict where the message is sent to; to stop an attacker mimicking your parent page. See the MDN documentation on postMessage for more details.
setHeightCalculationMethod(heightCalculationMethod)
Change the method use to workout the height of the iFrame.
size ([customHeight],[ customWidth])
Manually force iFrame to resize. This method optionally accepts two arguments: customHeight &customWidth. To use them you need first to disable the autoResize
option to prevent auto resizing and enable the sizeWidth
option if you wish to set the width.
1 2 3 4 5 |
iFrameResize({ autoResize: false, enablePublicMethods: true, sizeWidth: true }); |
Then you can call the size
method with dimensions:
1 2 3 |
if ('parentIFrame' in window) { parentIFrame.size(100); // Set height to 100px } |
Troubleshooting
The first steps to investigate a problem is to make sure you are using the latest version and then enable the log option, which outputs everything that happens to the JavaScript Console. This will enable you to see what both the iFrame and host page are up to and also see any JavaScript error messages.
Solutions for the most common problems are outlined in this section. If you need futher help, then please ask questions on StackOverflow with the iframe-resizer
tag.
Bug reports and pull requests are welcome on the issue tracker. Please read the contributing guidelinesbefore openning a ticket, as this will ensure a faster resolution.
IFrame not sizing correctly
If a larger element of content is removed from the normal document flow, through the use of absolute positioning, it can prevent the browser working out the correct size of the page. In such cases you can change the heightCalculationMethod to uses one of the other sizing methods, normally you will be best off selecting the max or lowestElement options to avoid cross browser differences.
IFrame not downsizing
The most likely cause of this problem is having set the height of an element to be 100% of the page somewhere in your CSS. This is normally on the html
or body
elements, but it could be on any element in the page.
Not having a valid HTML document type in the iFrame can also sometimes prevent downsizing. At it’s most simplest this can be the following.
1 |
<!DOCTYPE html> |
IFrame not resizing
The most common cause of this is not placing the iframeResizer.contentWindow.min.js script inside the iFramed page. If the other page is on a domain outside your control and you can not add JavaScript to that page, then now is the time to give up all hope of ever getting the iFrame to size to the content. As it is impossible to work out the size of the contained page, without using JavaScript on both the parent and child pages.
IFrame not detecting CSS :hover events
If your page resizes via CSS :hover
events, these won’t be detected by default. It is however possible to create mouseover
and mouseout
event listeners on the elements that are resized via CSS and have these events call the parentIFrame.size() method. With jQuery this can be done as follows, once you have set the enablePublicMethods option to true.
1 2 3 4 5 6 7 8 9 |
function resize(){ if ('parentIFrame' in window) { setTimeout(function(){ // Fix FireFox timing issue parentIFrame.size(); },0); } } $(*Element with hover style*).hover(resize); |
IFrame flickers
Some of the alternate height calculation methods, such as max can cause the iFrame to flicker. This is due to the fact that to check for downsizing, the iFrame first has to be downsized before the new height can be worked out. This effect can be reduced by setting a minSize value, so that the iFrame is not reset to zero height before regrowing.
In modern browsers, if the default height calculation method does not work, then it is normally best to use lowestElement, which is flicker free, and then provide a fallback to max in IE10 downwards.
1 2 3 4 5 6 |
var isOldIE = (navigator.userAgent.indexOf("MSIE") !== -1); // Detect IE10 and below iFrameResize( { heightCalculationMethod: isOldIE ? 'max' : 'lowestElement', minSize:100 }); |
Please see the notes section under heightCalculationMethod to understand the limitations of the different options.
ParentIFrame not found errors
To call methods in the iFrame, you need to set the enablePublicMethods option to true. TheparentIFrame
object then becomes available once the iFrame has been initially resized. If you wish to use it during page load you will need to poll for it becoming available.
1 2 3 4 5 6 7 8 |
if(top !== self) { // Check we are in an iFrame var interval = setInterval(function(){ if ('parentIFrame' in window) { clearInterval(interval); ... } },32); } |
PDF and OpenDocument files
It is not possible to add the required JavaScript to PDF and ODF files. However, you can get around this limitation by using ViewerJS to render these files inside a HTML page, that also contains the iFrame JavaScript file (iframeResizer.contentWindow.min.js).
Unexpected message received error
By default the origin of incoming messages is checked against the src
attribute of the iFrame. If they don’t match an error is thrown. This behaviour can be disabled by setting the checkOrigin option tofalse.
Browser compatibility
jQuery version
Works with all browsers which support window.postMessage (IE8+).
Native version
Additionally requires support for Array.prototype.forEach (IE9+) and document.querySelectorAll (IE8 Standards Mode). For IE8 force Standards Mode,
1 |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
and use the MDN PolyFill on the host page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if (!Array.prototype.forEach){ Array.prototype.forEach = function(fun /*, thisArg */){ "use strict"; if (this === void 0 || this === null || typeof fun !== "function") throw new TypeError(); var t = Object(this), len = t.length >>> 0, thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++) if (i in t) fun.call(thisArg, t[i], i, t); }; } |
PS:原文为官网文章。大致的解决方法如下:
1、在放Iframe的页面,宽度设置成百分比,scrolling设成no,引入iframeResizer.min.js脚本,并且进行初始化。
<iframe src=”http://anotherdomain.com/iframe.html” width=”100%” scrolling=”no”></iframe>
<script src=”../js/jquery.min.js”></script>
<script type=”text/javascript” src=”../js/iframeResizer.min.js”></script>
<script>iFrameResize()</script>
如果想进行DOM操作,可以参考如下参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
iFrameResize({ log: true, // Enable console logging enablePublicMethods: true, // Enable methods within iframe hosted page enableInPageLinks: true resizedCallback: function(messageData) { // Callback fn when resize is received $('p#callback').html( '<b>Frame ID:</b> ' + messageData.iframe.id + ' <b>Height:</b> ' + messageData.height + ' <b>Width:</b> ' + messageData.width + ' <b>Event type:</b> ' + messageData.type ); }, messageCallback: function(messageData) { // Callback fn when message is received $('p#callback').html( '<b>Frame ID:</b> ' + messageData.iframe.id + ' <b>Message:</b> ' + messageData.message ); alert(messageData.message); }, closedCallback: function(id) { // Callback fn when iFrame is closed $('p#callback').html( '<b>IFrame (</b>' + id + '<b>) removed from page.</b>' ); } }); |
2、如果是跨域,需要在被嵌入的页面,添加如下脚本:
<script src=”http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js”></script>
<script src=”js/iframeResizer.contentWindow.min.js” type=”text/javascript”></script>
【附】
官网:http://davidjbradshaw.github.io/iframe-resizer/
下载地址: