Let's get this out of the way. An iframe
is an inline frame that allows embedded HTML documents. This somewhat recursive definition covered 90% of pages I visited while learning about iframes. But the question remained - what is an iframe
?
This blog touches on the interesting things I discovered in search of a satisfying answer; the parallels between this 90s HTML tag and today's in Vogue technology, Chrome's amazing way of making iframes secure and whether iframes will be around for another thirty years.
A window to the past
Before iframes, there were frames. A frame
is a little window to a webpage. A frameset
element fits these little webpages into a bigger a webpage. For example, a frameset
could have a header, footer, navigation and content frame. Because each frame is a window, it has its own location and can change location independent of other frames. This allows parts of a website to change content and only download the resources for the new part. Thirty years later we call this code splitting and it's very cutting edge.
A document with a frameset is different to other HTML documents. These "frameset documents" can only have frameset or frame elements, no body or other HTML elements. This creates a problem where you're all-in on framesets and frames or not using them at all.
This sets the stage for the hero of our story. Enter the Inline Frame.
An iframe
is a frame that can be placed alongside other elements in "normal" HTML documents. It ushered in a new era of embedded content on the web. An iframe
is an encapsulation of HTML, CSS and JavaScript. A page can have many iframes so it is a reusable encapsulation as well. Through this lens, they look like something very familiar...
Are iframes the original component architecture that we love so much? It feels like we were so close to discovering the component architecture before we decided HTML, CSS and JavaScript must be kept separate from one another. What would the web look like today if we iterated toward separation of concerns rather than separation of technologies? These troubling exercises are left up to the reader.
So now we know what's on the tin, what's in the tin? Google Chrome produces over 60% of the world's iframes. Are these iframes humanely raised? What's the square-foot to iframe
ratio? I took a trip to Chrome to find out.
Behind the frame
As we touched on earlier, an iframe
is a little window that shows a web page. This is a decent way of reasoning about the implementation and performance characteristics. If there's a page with two iframes on it, that's like having three pages open.
To get a bit more detailed, we'll have to talk about how Chrome works. Chrome is a multi-process application. There's a "browser" process responsible for things like rendering the browser's UI and handling network requests. There are "render" processes responsible for everything related to a web page. The render process handles things like the DOM, CSSOM, V8 VM(s), painting pixels, making triangles from pixels and sending lots of triangles to the GPU. GPUs love triangles.
Modern versions of Chrome are built on the site-isolation policy. This means each site has its own render process. If you have ever wondered why your activity monitor looks like a Chrome ad, this is the reason. Having a render process per site is overwhelmingly a good thing. It brings the same sandboxing and safety guarantees that your OS makes about programs to websites. Feel good knowing there's nothing technically wrong with online banking and shopping on a dodgy e-commerce site at the same time.
iframes are no exception to the site-isolation policy. A render process gets created for each iframe
element. This isolates iframes from each other and the parent page. Again, this is a good thing for you and I. Chrome on the other hand has gone from 1:1 page-to-render process to 1:N page-to-render processes. This is an explosion in complexity.
A page with an iframe
always pays a memory overhead. There's overhead for a new process and essentials that are in every render process. Objects like Frame, Window and Document get created regardless of what's in the iframe
. On my computer, a render process for a "hello world" web page used roughly 17MB of memory. Each iframe
I added created another 17MB process. Like every webpage, the memory usage scales with how much DOM, styling and JavaScript the page has.
A page with an iframe
greatly increases the complexity of rendering that page. There's no single render process in control of rendering the entire screen. Chrome solves this by getting each render process to paint its local view of the world. Each render process passes that information to the browser process which composes the final result shown to the user.
A page with an iframe
suddenly makes handling user input much harder. When the user clicks somewhere on the page, the browser process works out what render process "owns" the part of the screen that was clicked on. Only once that is determined, the correct render process can start to handle the event.
On top of all this, iframes still want to talk to other frames! All of this incredible work to isolate frames from one another, then there's this requirement:
window.parent.postMessage('lol')
Think about the layers of computer required to implement this. This innocuous 'lol' goes from a thread running V8, sent over IPC, through the OS, back up to window.parent
's render process, to finally end up in that process' V8 thread. And there's no guarantee that the JS context is listening to the "message" event listener.
Rendering, responding to user input and implementing JavaScript APIs are all trickier with iframes. Many browser features we take for granted require Chrome to coordinate multiple processes.
iframe, therefore I am
Sadly, iframes are struggling to keep up with the demands of today's web. The rise of the web app has created a host of new requirements for iframes. For example, any web app that wants to allow 3rd party UI extensions - iframes are the de facto technology. This pushes past embedded content on a web page to embedded extensions in a web app. For this use-case, iframes are looking long in the tooth.
Take the description "single page application". This seems incompatible with an element that is literally another page. Terminology aside, the more integrated an extension the host web app, the more wrestling with the reality that an iframe
is a different frame. Selection, focus, layout, dialogs - all these things require coordination between the iframe
and the main frame.
"Isolated yet integrated" best sums up the mixed bag of UI extension requirements. WASM is a technology that supports this idea for code running in the browser. It's a sandbox with a controllable level of integration with the main JS context. Integration can look like calling WASM functions from JS, sharing memory between WASM and JS or a combination of both. An equivalent level of control isn't afforded to UI extensions.
What would that look like? Imagine if you could decide to have isolated DOM, common styles, a single window and some shared JS memory. Such granular level of control doesn't exist in browsers today. Web components provide more options, but not suited for sandboxing 3rd party JavaScript. Something like the extensible web could get us there, but remains an idea for now.
Regardless of what happens in this area, iframes are not going away anytime soon. Sentenced to support the requirements of the web thirty years ago. Bent and twisted to support the requirements of today's web. The iframe
is the jack of all trades. It's the whole expression that best tells the story of the iframe
. Jack of all trades, master of none - often better than master of one.
Thanks for reading!
If you liked this, you might enjoy reading about my "Haskell phase".
Resources
Here are some links to the resources I used to put this blog together.
Top comments (2)
iFrAmE iS mAgIc.
Insightful dissertation. Asking for more Haskell :)