Iframe Performance Part 2: The Good News

Max Rafferty
Slices of Bread
Published in
4 min readJan 21, 2021

This article is the third in a series about working with iFrames. The first, iframe: A Love Story, describes a brief history of the iframe, and how and why we need them at Bread. The second, part one of this article, describes and analyzes the performance issues that plague iFrames.

•✧─────────────✧¸.•´*¨`*•✿•*`¨*`•.¸✧─────────────✧•

Alternative Load Methods to the Rescue

One of the most powerful tools at our disposal when dealing with frames is the ability to utilize the src and srcdoc attributes to directly inject our markup rather than letting the iFrame handle the network portions of the operation. There are other techniques, like dynamically loading the elements after page ready, that can give us further flexibility, but we will focus on these new load methods as they are easy to implement across the board, and have a dramatic effect on load times. Other techniques have more caveats, but should be explored situationally.

Scenario 1: Data URI pages

Much like images, iFrames also have a src element and can have their content pages be base64 encoded as a Data URI. This takes some finagling, especially for larger pages with more special characters, but eventually you will end up with a very beautiful frame like the following:

<iframe src="data:text/html;base64,PCFET0NUWVBFIGh0bWw+PGh0bWw+PGhlYWQ+DQogIDxtZXRhIGh0dHAtZXF1aXY94oCdY29udGVudC10eXBl4oCdIGNvbnRlbnQ94oCddGV4dC9odG1sOyBjaGFyc2V0PVVURi04Ij48dGl0bGU+aUZyYW1lIFBlcmZvcm1hbmNlPC90aXRsZT4NCjxib2R5Pg0KICA8YSB0aXRsZT0iTWljaGFsIEtsYWpiYW4sIENDIEJZLVNBIDQuMCAmbHQ7aHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzQuMCZndDssIHZpYSBXaWtpbWVkaWEgQ29tbW9ucyIgaHJlZj0iaHR0cHM6Ly9jb21tb25zLndpa2ltZWRpYS5vcmcvd2lraS9GaWxlOiUyMkV2ZXJ5dGhpbmdfaXNfR29pbmdfdG9fYmVfQWxyaWdodCUyMl9hcnR3b3JrLF9DaHJpc3RjaHVyY2hfQXJ0X0dhbGxlcnksX0NocmlzdGNodXJjaCxfTmV3X1plYWxhbmQuanBnIj48aW1nIGFsdD0iJnF1b3Q7RXZlcnl0aGluZyBpcyBHb2luZyB0byBiZSBBbHJpZ2h0JnF1b3Q7IGFydHdvcmssIENocmlzdGNodXJjaCBBcnQgR2FsbGVyeSwgQ2hyaXN0Y2h1cmNoLCBOZXcgWmVhbGFuZCIgc3JjPSJodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zL3RodW1iLzIvMjEvJTIyRXZlcnl0aGluZ19pc19Hb2luZ190b19iZV9BbHJpZ2h0JTIyX2FydHdvcmslMkNfQ2hyaXN0Y2h1cmNoX0FydF9HYWxsZXJ5JTJDX0NocmlzdGNodXJjaCUyQ19OZXdfWmVhbGFuZC5qcGcvNDA5NnB4LSUyMkV2ZXJ5dGhpbmdfaXNfR29pbmdfdG9fYmVfQWxyaWdodCUyMl9hcnR3b3JrJTJDX0NocmlzdGNodXJjaF9BcnRfR2FsbGVyeSUyQ19DaHJpc3RjaHVyY2glMkNfTmV3X1plYWxhbmQuanBnIj48L2E+DQogIDxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij4vLzwhW0NEQVRBWw0KICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgKGV2ZW50KSA9PiB7DQogICAgICB3aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKCJmcmFtZSBsb2FkZWQiLCAiKiIpOw0KICAgIH0pOw0KLy9dXT48L3NjcmlwdD4NCjwvYm9keT48L2h0bWw+">The “iframe” tag is not supported by your browser.</iframe>

The theory here is to remove the network element entirely. If that is a part of the problem, then we should see notable improvement with this approach.

Set up the same way as our previous experiment, our first test shows promising results:

While an astute reader will note that “of course removing the network call speeds things up”, there is no reason that this isn’t accomplishable in nearly every situation. These strings can be included in the main JS or HTML payloads without much difficulty. In any event, the result is dramatic. With the exception of our interesting outlier, performance is improved 4x consistently with this technique.

Scenario 2: srcdoc

This approach is nearly identical to the last, however it uses raw HTML in the srcdoc element rather than an encoded document in the src. The srcdoc element is very interesting. It was designed to provide an “override” for the src element to increase browser support, which is no longer an issue, but it is still useful if we want to manually populate our frame with somewhat more readable markup. This is a little easier to put together than the prior example, though you’ll frequently need to escape quotes:

<iframe srcdoc=’<!DOCTYPE html><html><head><meta http-equiv=”content-type” content=”text/html; charset=UTF-8"><title>iFrame Performance</title><body><a title=”Michal Klajban, CC BY-SA 4.0 &lt;https://creativecommons.org/licenses/by-sa/4.0&gt;, via Wikimedia Commons” href=”https://commons.wikimedia.org/wiki/File:%22Everything_is_Going_to_be_Alright%22_artwork,_Christchurch_Art_Gallery,_Christchurch,_New_Zealand.jpg"><img alt=””&quot;Everything is Going to be Alright&quot; artwork, Christchurch Art Gallery, Christchurch, New Zealand” src=”https://upload.wikimedia.org/wikipedia/commons/thumb/2/21/%22Everything_is_Going_to_be_Alright%22_artwork%2C_Christchurch_Art_Gallery%2C_Christchurch%2C_New_Zealand.jpg/4096px-%22Everything_is_Going_to_be_Alright%22_artwork%2C_Christchurch_Art_Gallery%2C_Christchurch%2C_New_Zealand.jpg"></a><script type=”text/javascript”>//<![CDATA[window.addEventListener(‘load’, (event) => {window.parent.postMessage(“frame loaded”, “*”);});//]]></script></body></html>’>The “iframe” tag is not supported by your browser.</iframe>

This one may look a little strange given that it is a string of escaped HTML inside of another HTML tag. It is not quite as concise as our prior example, but some may consider it easier to write by hand. Note that we needn’t include a complete document as we have here; fragments are acceptable.

While not quite as effective as the encoded src, which is mildly surprising given that the data URI must be parsed and decoded twice, this is still better than the control. Performance here is closer to 2x, but if for whatever reason base64 encoding your markup is unappealing, this technique is still viable. This could be the case if you are generating your markup on the fly or downloading it separately unencoded.

These results are very encouraging. At face value, it appears that as one might expect, removing the network does significantly increase iFrame performance. By combining these with lazy loading, as well as other more common tricks to reduce the apparent load time, we can get close to the appearance of near-instantaneous loading of iFrames.

--

--