fix(portal-shell): dark mode actually applies to component-scoped surfaces #87
Reference in New Issue
Block a user
Delete Branch "fix/portal-shell/dark-mode-scoping"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bug
Three component stylesheets (
app.scss,sidebar.scss,theme-switcher.scss) carried:where(.dark) &rules to react to the<html>.darkclass — the same pattern Tailwind uses internally. Angular's emulated CSS encapsulation descends into:where()and rewrites its contents with the_ngcontent-XXXscoping attribute, so the produced selector looked like:<html>carries.darkbut no_ngcontentattribute — the rule never matched.Visible symptom: the main page background stayed light even when
.darkwas on<html>and every Tailwinddark:utility in the templates was working correctly. Sidebar hover/focus/active states and the theme-switcher menu surface had the same bug.Fix
app.scssandsidebar.scssswitch to:host-context(.dark). The Angular compiler recognises this directive and expands it without forcing the ancestor (<html>) to carry the scoping attribute. Compiled output:The second selector matches
<html>.darkas an ancestor of<app-root>(the host) — exactly what we want.theme-switcherswitches toViewEncapsulation.None. Its CDK menu opens in an overlay portal appended to<body>— outside the component's host subtree — so even:host-context()would miss it. With encapsulation disabled, the styles emit globally; the BEM-style class names (.theme-switcher__menu,.theme-switcher__item, ...) keep the rules contained without leaking.Drive-by
.header__logo-zone. The visible hairline above the sidebar was extra noise — the alignment of widths already carries the visual relationship to the rail below.Why not also rip out the
dark:Tailwind utilities used in the templates?They work. They're emitted into the global Tailwind sheet, sit outside view encapsulation, and already handle the
.darkancestor lookup via their own selector (:where(.dark, .dark *)). The bug was specifically about component-authored CSS inside an SCSS file under emulated encapsulation.Test plan
pnpm exec nx run-many -t lint test build --projects=portal-shell— green (33 / 33 specs).:host-context(.dark)expands to both.dark[_nghost-XXX]and.dark [_nghost-XXX]selectors, no_ngcontentattribute leaked into the.darkportion./shows the dark page background; sidebar hover / active / focus visibly switches; theme-switcher menu opens with the dark surface.