catalog icon indicating copy to clipboard operation
catalog copied to clipboard

iframes vs. CSS-in-JS

Open jstcki opened this issue 6 years ago • 3 comments

This is a long-standing issue with components which are dynamically injecting styles into the page at the time when they're rendered (a.k.a CSS-in-JS). When using the HTML/React Specimen in with either the frame or responsive option, dynamic style injection is a problem because styles are always inserted outside of the dynamically created iframe and style updates are not reflected in the Specimens.

To make this problem worse, most styling libraries use different injection techniques from each other and also depending on if they're running in development or production mode.

In development, styles are usually injected by adding new <style> tags to the head or by updating the textContent of an existing <style> tag.

In production, most of the existing libraries use CSSStyleSheet.insertRule()

Current situation

At the moment, <style> and <link> tags from the main document are cloned into the iframe at the time it's mounted or updated. This is a pretty blunt approach but works fine if all styles are already there. Unfortunately, sometimes styles are injected after the iframe has rendered.

Possible approaches

Dealing with the problem of style tags being appended or their content being modified (i.e. development mode) is quite straightforward: use a MutationObserver to watch for changes of the main document's head, and clone styles if necessary.

Dealing with insertRule is another beast because there's no way to observe style changes made with it (at least not that I'm aware of)! The only way to detect this would be to register a callback with the styling library – an approach taken by react-popout-component. But I don't think any popular library supports that yet.

The only approach that comes to my mind that doesn't feel like a hack is to not use dynamically created iframes but actual iframes (which would also remedy #340). This would mean rendering each Specimen on a separate route and embed it in a regular iframe. But extracting Specimens at runtime would be quite complex at the moment. Even if that's possible, pages containing lots of regular iframes tend to load quite slow as each iframe creates its own request(s) (see https://statistikstadtzuerich.github.io/sszvis/#/beginners for example). One possibility to avoid the extraction complexity issue is to require the user to create separate "pages" for responsive Specimens.

So at the moment, I don't see a solution that would Just Work™ and am looking for input on this issue. Any help in finding a good solution is greatly appreciated! 🙏

P.S.: Why use iframes at all? Because it's the only way getting styles like position: fixed and viewport units vw/vh working.

jstcki avatar Feb 25 '18 21:02 jstcki

Hi @herrstucki Can we split this fix into two fixes? The first fix for running in dev mode and with versions that do not use the insertRule. And the second fix for when insertRule is used.

Stan-Che avatar Jul 19 '18 23:07 Stan-Che

@herrstucki Could you please have a look and share your opinion on this PR. I would like to help to solve this issue.

Stan-Che avatar Jul 23 '18 22:07 Stan-Che

https://webkit.org/status/#feature-visual-viewport-api

gaui avatar Jul 31 '18 01:07 gaui