Why is my Web Component inheriting styles?
Tue Mar 26 2019
One of the great features of the Shadow DOM in Web Components is that styles are encapsulated to the component - you can style your component without worrying about any specifier (
class, etc.) conflicts or styles 'leaking out' to other elements on the page.
This often leads to the belief that the reverse is true - that styles outside of the component won't cross the Shadow boundary and 'leak in' to your component. However this is only partly true.
While specifiers do not leak in to your component (e.g. a color applied to an
p element in a style rule outside of your component won't effect any
p elements in your Shadow DOM, although the rule will be applied to your Light DOM, or slotted content), inheritable styles applied to any elements containing your component will be applied to both your Shadow and Light DOM.
Inheritable styles are those that are defined on a parent that are then inherited by child elements. The most obvious inheritable styles are those defined on the
body tags. Taking
color as an example, if there is a
color: green set on the
body (which is a container for every element on the page), this will be inherited by all elements on the page, including Web Components, unless overriden by another more specific rule.
Inheritable styles are necessary so we don't, for example, have to write a
color rule on every element. But not all styles are inheritable, otherwise a
border style on one element would be inherited by all its children:
Rules set in the Shadow DOM act in the same way - inheritable styles are applied to all children (Shadow and Light DOM), so adding a
color: red to our Shadow DOM:
The chosen ones
So which styles are inheritable, and which are not? Well these are all defined by the CSS spec. The most common ones are:
So that's why these styles do leak into your Web Component.
What if I don't want my component to inherit from its parent?
Well you're in luck, you can reset all inheritable styles for a component (Shadow and Light DOM) using
all: initial, which resets the styles back to the CSS defaults or those defined in the browser 'user agent stylesheet'. Note that outside specifiers matching in the Light DOM will not be reset.
What if I want to style my component from outside?
Well that's where CSS custom properties come in, along with the new
::theme pseudo-elements, and I'll cover that in an upcoming post.
If you have any feedback or questions I'd love to hear them @lamplightdev.