Goodbye iframes

or: How I learnt to Stop Worrying and Love the Shadow Dom

Photo by Matthew Henry on Unsplash

The downsides of iframes

Research possible options for replacing iframes

The technical challenges of using iframes

  • Polyfills - we considered webcomponents-lite.js, webcomponents-sd-ce.js bundle(shadyDOM/CSSand custom elements only), webcomponents-hi-sd-ce.js bundle(HTMLimports, shadyDOM/CSS and custom elements), shadyDOM/CSSshims, and webcomponents-loader.js. For our purposes none of these worked well enough to continue into production: There was leakage of CSS and JS. Either just leakage in, just leakage out, or both. For our purposes, since we would be maintaining the iframe format for syndication, we made a decision to serve the iframe version to unsupported browsers: those that do not support document.head.attachShadow.
  • document.querySelector - The Shadow DOM doesn’t have access to document so document.querySelector() and document.querySelectorAll() do not work. Therefore we had to rewrite all of our in-house vanilla JS components to initialise with a scope (defaulting to document) that would take the shadow root returned from attachShadow. This was a little painful and also means we have to be careful when using external libraries.
  • media queries - with our content being used on mobile, desktop pages with a right hand column, desktop pages without a r/h side and full-width full-bleed pages, we need to be aware of the size of our content and enable media queries where applicable. Since our content is hosted by others who are in charge of the breakpoints, we have, in the past, used media queries to determine the width of our content in relationship to the page. With iframes, media query would give us the width of our content, with shadow dom media queries give us the width of the device itself. This is a huge challenge for us. We now have no way of knowing how big our content is when it’s served and have to ensure that our content is so pliable that it is perfect at every pixel width, rather than 3 or 4 widths we were used to. The good news is that there is a solution for our problem in element queries. The bad news is that no browser supports them yet.
  • Leakage - By nature there is almost zero CSS leakage, but there is a modicum of JS leakage when using, for instance, indentical libraries. We could counter this with namespacing and explicit context, so it became a non-issue. Leakage with polyfills, however, was excessive to the point of making the Shadow Dom unusable. We thought that closed mode for Shadow Dom might have been the solution, but it turns out that it doesn’t work how one might have thought, as Leon Revill explains here.
  • getBoundingClientRect - getBoundingClientRect().top works differently inside the Shadow DOM. You get the position relative to the scroll, as if the element was part of the page(if it’s in the iframe you get the offset compared to the top of the page). Also on Firefox we have seen scroll return a string rather than a number, which is confusing. We have built in workarounds for both.
  • Anchor points - window.location.hash = ‘#example’ - doesn’t jump the page down as expected, and doesn’t then change the focus (so unable to create a ’skiplink’, for example).
  • React can’t handle events within the shadow DOM - so click, submit, hover etc will not work with React.

The results




Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Toby Cox

Team lead for BBC Visual Journalism. Formerly Senior Developer at Netro42.