TL:DR: I propose myIframeElement.promote()
to navigate a browser from page A to page B, where page B is already loaded and rendered as an iframe on page A, by “promoting” the IFRAME to be the top level browsing context. Read on!
Recently, the W3C TAG has been concerned about the increase in ‘walled garden’ content ecosystems, notably Google’s AMP cache and carousel, but also Facebook instant articles, Apple News and other similar products. Where these systems are implemented on the web they may choose to reproduce a third party’s content within their own UI, or load the third party into an IFRAME, in order to provide a faster, reliable loading experience. These practices arise from a legitimate and reasonable desire to improve the loading speed of pages (especially news articles) that you might want to navigate to from a search result page or newsfeed.
In AMP’s case, this works by:
- Loading a number of search result target pages in hidden iframes while the search results are displayed
- Capturing clicks/taps on the search result elements
- In response, displaying the relevant already-loaded IFRAME full-screen.
- Updating the URL to reflect the state change.
However, this approach suffers from some severe negative effects, notably that the third party’s origin is not preserved. The referring party can only update the URL to a path on their own origin, resulting in a URL such as nytimes.com/path/to/article
displaying as something like google.com/s/amp/nytimes.com/path/to/article
. The destination page is unable to access client-side resources and permissions that are attached to their origin, and the unclear attribution has significant implications for the provenance and trustworthiness of the content.
I’ve previously proposed a limited resurrection of the <link rel="prerender">
tag, but the following may be a better solution:
I propose that we create a promote
method of HTMLIFrameElement.prototype
that performs the following steps:
- replace the current top level browsing context with the browsing context of the IFRAME, without reconstructing the DOM of the frame. If the IFRAME does not have the right size or position, the browser should perform a relayout and paint as would happen if the viewport were resized by the user.
- reevaluate the CSS OM of the page to remove any influences resulting from the CSS of the parent page (which might, for example, have made the IFRAME invisible)
- reevaluate any origin-level policies that may have previously been applied to the page when it was being framed by another origin (eg Referrer policy, feature policy or CSP). For example, a page that may not be permitted to use geolocation when framed might be allowed to do so once promoted.
- update the URL bar to the URL of the new page
- Trigger the
unload
event on the referring page and perform any actions normally associated with unloading a document - Enter the unloaded document in the history
If a user invokes the browser’s ‘back’ action after an iframe promotion, the browser should reconstruct the prior page. Browsers that retain the prior page’s DOM might choose to ‘reframe’ the active DOM back into the IFRAME element of the prior page’s DOM, otherwise both the prior page and the IFRAME should be reloaded.
Example code:
// Pre-render the top three search results into hidden iframes
searchResults.querySelectorAll('a').slice(0,3).forEach(el => {
const prerenderIframe = document.createElement('iframe');
prerenderIframe.src = el.href;
prerenderIframe.classList.add('prerender-frame');
el.prerenderIframe = prerenderIframe;
});
// On click, promote the iframe if there is one
searchResults.addEventListener('click', e => {
const linkEl = e.target.closest('a');
if (linkEl.prerenderIframe) {
e.preventDefault();
linkEl.prerenderIframe.promote();
}
});
You could imagine that developers might want to animate a transition to the iframe in some way, which could be accomplished easily with existing CSS transitions.
This solution has privacy implications - the referring site may be initiating fetches to the target site before the user has indicated an intent to go there, so there is also a need for a mechanism that enables the referring site to cache the target site’s content but retain the ability to run that content within the context of the target origin. Therefore the solution proposed here works well in conjunction with signed packages. Without packaging, promotable iframes would still work if the referring site, or a partner, to host a subdomain of the target site’s origin, in order to ensure that prefetch requests do not provide privacy-compromising information to the target site’s owners.
I’ve mostly considered this as a solution for AMP, but there are use cases beyond pre-loading seach results, notably in advertising: responsive ads might achieve a faster, more seamless transition from publisher site to advertiser site if the ad iframe were simply promoted rather than navigating the browser to a new page.
Cheers,
Andrew