Frames and iframes

  1. Basic (grandpa’s) frames
  2. Inline frames or iframes
    1. Removing the native frameborder
    2. Iframe src property
  3. Accessing the inner document
  4. Access via window.frames
    1. Iframe name attribute in IE
  5. Frames hierarchy
  6. Iframe onload event
  7. HTML5 seamless and sandbox attributes

Frames is an old-school way to split a browser window in several zones, so called frames, where each frame behaves as a separate window.

Basic (grandpa’s) frames

The HTML for basic frames could look like this:

<HTML>
  <FRAMESET cols="20%, 80%">
    <FRAME src="left.html">
    <FRAME src="right.html">
  </FRAMESET>
</HTML>

The HTML document which as frameset instead of body splits browser window in sections. In the example above, there are two of them.
The left one is 20% of width, it loads left.html, the right one is 80% and loads right.html.

The frameset element can be nested and provides several ways to split the window: either vertically or horizontally. Frames are allowed to contain frames. So, the browser window may be split into cells the way you like.

Each frame loads separate document. Reloading or navigation of a frame does not affect other frames.

The basic frames are deprecated. The frameset tag and it’s helper tags frame/noframes are removed from the modern HTML5 standard.

Actually, basic frames are out of use by now. They are given here for historical reasons and completeness only. So, we’ll move forward to more advanced frames stuff which is really used.

Inline frames or iframes

Inline frames provide a way to embed another page as a rectangular subwindow. For instance, here is an inline frame with top of http://javascript.info:

<iframe src="http://javascript.info"></iframe>

In action:

Usually you’d also set width, height etc. Almost all properties can be assigned with CSS, with a minor exception of frameborder.

Removing the native frameborder

To remove the border around the iframe in an IE-compatible way, it should be set as an attribute.

In the example below, the first frame is bordered by default, the second is unbordered using CSS, and the last one has frameborder="0" which will work for IE (including IE9).

Check this example in IE to see that only the last way works.

<style> * { width: 100px; height:40px } </style>
<ol>
  <li><iframe src="JavaScript:'content'"></iframe></li>
  <li><iframe src="JavaScript:'content'" style="border:0"></iframe></li>
  <li><iframe src="JavaScript:'content'" frameborder="0"></iframe></li>
</ol>

So, one usually sets frameborder="0" and applies custom border with CSS if needed.

Iframe src property

As you noticed in the example above, the src attribute may be either standard or JavaScript:.... In the latter case, the code is executed and the result is used as content.

Iframe without src

An iframe without src attribute is wild and awry.

It leads to problems in older browsers. In newer IEs it has problems with HTTPs: iframe without src gives non-secure warnings on SSL-enabled page.

The empty src="" won’t work, because it actually means to load the URL referenced by “”, that is the current page.

To create an empty iframe which works well on IE HTTPs, one should use src="JavaScript:''" syntax.

Also, the src attribute, like most standard attributes is accessible as DOM property: iframe.src, so the DOM creation syntax is perfectly valid:

var ifr = document.createElement('iframe')
ifr.src = '/my/url' 
document.body.appendChild(ifr)

Accessing the inner document

An iframe element is just a DOM element, like any other. The only difference is that there exists a related window object. It is referenced in contentWindow property.

So, iframe.contentWindow.document will be the inner document.
You can access it or modify from parent window if both iframe and the parent come from one domain/host/port (security limitations are discussed more in detail in the next sections).

In the example below, the function makeGreen accesses the document of the iframe element and modifies it.

<iframe src="JavaScript:'content'" style="height:60px"></iframe>

<script>
  function makeGreen() {
    var iframe = document.getElementsByTagName('iframe')[0]
    var doc = iframe.contentWindow.document
    doc.body.style.backgroundColor = 'green'
  }
</script>

<input type="button" onclick="makeGreen()" value="click me">

Note that the HTML ‘content’ is the example above is not valid. Hence the iframe window will be rendered in quirks mode. But browser always ensures the minimal structure.

Any html page has the document.body after is has finished loading.
Even the most invalid one.

Access via window.frames

There is a special property window.frames which allows to access iframe window objects directly.

There are two forms of access:

  1. window.frames[0] - access by number
  2. window.frames['iframeName'] - access by iframe name

<iframe src="JavaScript:''" style="height:80px" name="iframeName"></iframe>

<script> 
function check() {
  alert(frames[0] === frames['iframeName'])
}
</script>

<input type="button" onclick="check()" value="click me!">

Try it, click on the button above. You’ll see that frames can be accessed both by number and by name. Funny, but it works.

Iframe name attribute in IE

The name attribute contains the name of the corresponding window. It works seamlessly on all browsers excepts IE<8 (and IE8 compat mode).

In older IEs, there are quite a few bugs related to assigning name in run-time, so the typical workaround is to create an iframe with name.

// IE proprietary createElement syntax allows attributes
document.createElement('<iframe name="myiframe" src="JavaScript:\'\'">')

.. Or you can just use innerHTML.

Remember that as a mighty workaround for all name-related problems.

Frames hierarchy

A window has frames collection to access the frames.

The frames, in their turn, has parent property which refers to the enclosing window:

window.frames[0].parent === window  // always true

Also, for the case when frames are nested, there is an easy way to get the topmost frame using the top property.

// (assuming nested frames exist)
window.frames[0].frames[0].frames[0].top === window

The top property also gives an easy way to check if the page is inside a frame.

The example below shows alert in such case and forces the document to show in topmost frame by putting it’s URL into top.location:

if (window !== top) {
  alert('The script is executed in frame!')
  top.location = window.location+''
}

Iframe onload event

A window has onload event which fires when it is loaded completely. But in case of iframe, there are two ways to catch onload:

  1. Assign the handler to iframe window, like frames[0].onload = ...
  2. Assign the handler to iframe DOM element: iframeElem.onload = ...

The difference is demonstrated in the example below:

<iframe src="http://google.com/" name="google" style="height:100px"></iframe>

<script>
  // set onload on element
  document.getElementsByTagName('iframe')[0].onload = function() {
    alert('Frame element loaded')
  }

  // set onload on window
  frames[0].onload = function() {
    alert('Window loaded')
  }
</script>

Run the example above. You’ll see that only the iframe attribute works, because it doesn’t depend on cross-domain access policy like setting onload on a window from another domain.

So, shortly, the iframe.onload is more reliable then iframe.contentWindow.onload.

HTML5 seamless and sandbox attributes

The seamless and sandbox attributes are new in HTML5.

At the time of writing (Jan 2011), the seamless is not supported. It should integrate the iframe seamlessly into page by removing border and applying CSS styles of the parent as if the iframe were just an element.

The sandbox is simpler to implement. It is supported by the recent Webkit (e.g in Chrome). When the sandbox attribute is set, the iframe content is treated as being from a unique origin, forms and scripts are disabled, links are prevented from targeting other browsing contexts, and plugins are disabled.

So, the following iframe lives in a separate, very limited world. Check it using the latest Chrome:

<iframe sandbox src="/files/tutorial/window/sandboxed.html"></iframe>

The sandbox attribute may contain space-delimited flags which relax the limitations:

allow-same-origin
Doesn’t force the unique origin for iframe contents.
allow-top-navigation
Allows iframe to navigate parent context, e.g. change parent.location.
allow-forms
Allows forms submissions from inside iframe.
allow-scripts
Allows scripts execution. Still, scripts are not able to create popups.

The aim of sandboxing is to limit. It can’t lighten default limitation, like make an iframe from another domain to appear from the same origin.

All it can do is limiting, with possible exceptions, like:

<iframe sandbox="allow-same-origin allow-forms" src="do.php"></iframe>

The iframe above will have JavaScript disabled, but may remain in same origin and the forms may also be submitted.

Tutorial

Donate

Donate to this project