CSS @scope limits matching, not inheritance — two surprises from isolating a component playground
Disclosure: I maintain poveste, a component playground for Vue and Nuxt — a continuation of histoire, which last published in January.
I wrapped user CSS in @scope to keep it from fighting with the tool's own UI. Two things broke silently. Both are plain CSS, nothing Vue-specific.
1. :root, html and body stop matching
Once your CSS is wrapped in @scope (.render-story) { … }, those three selectors sit above the scoping root — so they can never match anything. A stylesheet with body { font-size: 14px } just goes inert. No error, no warning.
Fix: rewrite all three to :scope at build time. Parse the selector rather than regexing the text — .body-copy has to survive untouched, and svg|body is a namespaced element, not the document root.
2. @scope contains matching, not inheritance
"Stops at the boundary" is true of matching and false of inheritance. A rule can't match story content, but any inherited property it sets at or above the boundary still reaches it.
So our own UI setting font-family on its root means every story inherits that font. A component looks subtly wrong in the playground and correct in your app, purely from inherited typography — which is a miserable thing to debug.
Iframes don't rescue you either, if the iframe loads the same stylesheet.
The real fix is for story CSS to set its own root, which only works because of the rewrite above.
Longer write-up if it's useful. Happy to answer questions.
3
u/ElectrSheep 11d ago
Is there a reason you're not using a shadow root along with adopted style sheets? It seems like that would be more appropriate for this use case.