Seamless IFRAMEs: not quite seamless?

by Andrew Betts,

Another day, another new exciting web technology.

I was first alerted to this spec by Luke Kavanagh in our interactive graphics team, and found an excellent presentation on seamless by Ben Vinegar. The premise of seamless is pretty simple: make it possible for an IFRAME to resize itself to fit its content, and inherit style rules from the parent frame. People have been wanting this for years, because the lack of these two features are effectively negative side effects that we endure in order to get the major benefit of an iframe – sandboxing.

Interactive graphics is a great example of a use case – say you have a really complex web application, like the FT web app, and for a single story, you want to embed some kind of interactive chart widget thing. But the interactive thing needs to be designed and built quickly, possibly by a third party, and frankly you don’t trust these rapidly built interactives not to mortally wound your beloved app. Solution – pop the interactive in an IFRAME. And with seamless we potentially avoid the need for the IFRAME and the parent page to do some awkward cross-domain postMessage to negotiate the resizing of the frame, or the iframe needing to load CSS files that the parent already has.

So, what’s the problem?

Multiple distinct features

The simple act of adding the seamless attribute to an iframe turns on all of this:

  1. Links within the IFRAME by default navigate the parent frame, not the IFRAME.
  2. Media queries located inside the IFRAME will evaluate media attributes of the parent frame, not the IFRAME (so eg width will refer to the width of the parent frame’s viewport, not the viewport of the IFRAME)
  3. Styles defined in the parent frame also apply to the iframe
  4. The IFRAME’s default width and height behave as if the IFRAME were a normal block level element

This all seems to be sensible, and if you think of IFRAMEs just as sandboxes or a client side include mechanism for populating a block element, then these features normalise that behaviour. But we’re all used to the way that IFRAMEs work today, so attaching all these new features to a single switch seems like a bad call to me. Especially as some of the features change the way the parent affects the child (style bleed-through) while others change the way the child affects the parent (dynamic sizing). And it’s not even a comprehensive set of features, because seamless does not trigger the same priveleges as allowtransparency and allowfullscreen. I’d like to see features available with that level of granularity consistently, rather than bundling a relatively arbitrary group of features into one flag.

Nonsensical media queries

The media queries thing sounds sensible, but if an IFRAME is 300px wide, and the parent is 1000px wide, media queries in the IFRAME are going to style content based on a width of 1000px, even though a 100% wide block level element will still only be 300px wide. In fact, this rule doesn’t seem to be respected in Chrome Canary right now (as of 8th December) because a media query on min-width seems to trigger based on the width of the iframe, not the parent frame. I think this seems right. Media queries defined in the child frame ought to be executed based on the media features of that frame. If you want to affect the frame’s styling based on media features in the parent, you can still do that by running the media query in the parent frame.

A related issue is that the child frame seems to have no practical way of determining whether it is being included seamlessly. A frame might well wish to alter its behaviour if it knew it was seamless.

Event model

Seamless seems to have no effect on the event model. That means that, for example, a touchstart event occuring in the parent frame would not fire in the child, although the touch might end in the child frame.

Modals

Seamless iframes can’t paint on areas of the document outside of the frame, which prevents them from, for example, displaying modal dialogs. While you might quite reasonably want to limit the frame’s ability to do this, for it to be truly considered part of the parent page, it ought to be possible for it to have this ability.

Same-origin handicap

In order for an IFRAME to be seamless it must have the same origin as the parent. But that also destroys most use cases for seamless. Our interactive graphics example still works, but Ben’s use case is adding a third party commenting widget to the end of your page (he works for Disqus), and as the spec stands a conformant browser would refuse to recognise that IFRAME as seamless. So Disqus is stuck with a regular IFRAME that needs to ask its parent to resize it. And in order to do that Disqus still need to put JavaScript on your page, as well as in the IFRAME.

The widget use case

On the other hand, in relation to third party widgets generally, it’s also not at all clear that companies like Disqus would actually be better off with a seamless IFRAME as the starting point to include their widget. By including a script from a third party, a site owner is granting complete control over their DOM to the third party (whether they’ve considered the implications of that is another matter entirely, but it’s still common practice today). However, by including just an iframe, seamless or otherwise, the site owner is only granting control over one element of their page to the third party, and is sandboxing them into that element.

This is really positive for security and reliability of the web platform in general, but it changes the way that companies like Disqus will advise site owners on integrating their apps. Give out a badly considered script tag, and it’s no big deal – you can serve some script that fixes it. Give out a badly considered iframe tag, and you’re in trouble – only the site owner can fix that because your script will run in the iframe, not in the parent page where it can affect the attributes of the iframe itself. Nevertheless, this is what we ought to be doing, so features like seamless need to take these use cases into account. Clearly with the same origin rule, they currently don’t.

Possible solutions

I hate griping without offering solutions, but I don’t have a clear idea of what would be better. We could certainly make some changes to seamless, like more granular controls, lifting the same-origin restriction, and adding flags to integrate the event model and allow positioning of elements outside the iframe’s document. But it’s possible that some use cases might be better served with another solution, like perhaps a remotely loaded web component.