Donut scope is all about picking where a scope starts and ends. We want to apply styling to a certain area (the 'donut'), while allowing content inside of that area to be unstyled (the 'donut hole'). The 'donut hole' is where user-created content lives, whether that be:
Think of a Tabs component, where the individual Tab buttons and Tab Panels require styling, but content within should be unopinionated.
This helps work against the cascade - you're basically asking for a certain range to cascade in, but stop before the internal slot.
This is achievable with the [[20211115082404-css-not-selector]] in some forms:
foo :not(.foo .foo *)
to match things inside one .foo wrapper but not two.container :not(.content *)
to get simple shallow donut scopeThe latter of these two doesn't seem to work without passing two selectors: .content, .content *
. Unsure why, but the behaviour of :not
is a bit more confusing when no element is passed before the :not
.
article p:not(blockquote *)
would match all p
elements inside of an article
, but not descendents of a blockquote
.