Astro's scoped styles vs. runtime-created DOM
(Sample post — placeholder content for the new posts collection.)
Astro scopes every <style> block to the elements present in the component template by
stamping them with a generated attribute. That’s great until your page builds DOM at
runtime: document.createElement produces elements without the scoping attribute, so
your carefully written rules silently never match. No error, no warning — the element
just renders unstyled.
This bit three separate variants on this site before the pattern was written down:
- TerminalBoot’s terminal lines lost their phosphor colours.
- TypeSpecimen’s per-letter transforms did nothing because
display: inline-blocknever applied. - PaperFold’s facets collapsed to
width: 0.
The fix is the :global() wrapper:
/* Created in JS, so it must be :global() */
:global(.line) { white-space: pre-wrap; }
The better fix, where possible, is to keep the elements in the template in the first place and toggle them with classes or attributes — then the scoping just works, and you keep the isolation benefits you chose Astro for.