Layering Styles
While playing around with custom elements I hit a bit of a weird quirk. I had a sign in page which was just a heading and a button.
Nothing crazy. This was all at the top level of the page. To organise my code a little differently, I moved these elements into a component, lets call it signin-screen.
The result was that some style’s stuck and some were lost.
The reason the styles were lost is because I used shadow DOM to pull in the button and header, which results in the component having encapsulated styles. To phrase it another way, the component has full control of the styling of it’s shadow DOM (Apart from the color of the heading, which irks me because it’s an inconsistency — bleurgh — but all other page styles were blocked / not applied).
I started talking to Rob Dodson about all this. Rob pointed out that in people got around this by using a “deep” selector, which would pierce the encapsulation, allowing you to style elements inside of a components shadow DOM. It’s easy to see how this would get abused and has been removed from the spec. Plus, I’m pro style encapsulation, there are scenarios I can picture where the component will want to block a consumers styles from bleeding in.
One way to solve this problem is to use CSS variables (a.k.a custom properties) which allows a consumer of the component to pass in values into the components styles. I’ve created a crude diagram to illustrate this scenario.
Elements not in the shadow DOM get the User Agent Styles + Page Styles while a custom element using Shadow DOM gets the User Agent Styles + Component Styles. The component can allow CSS variables to be taken from the page’s styles and used inside the components styles (It’s a bridge / contract between the page’s styles and the component’s styles based on the expected CSS variable names).
This is a good solution but has one flaw. The author has to write their CSS to allow every possible CSS property to be definable and likewise, the consumer has to write out every CSS variable they want to define. This isn’t a terrible burden, but each component is likely to have difference CSS variable names, meaning styles for a button across components will need to be duplicated for each component (until common practices are formed).
Get Matt Gaunt’s stories in your inbox
Join Medium for free to get updates from this writer.
Going back to my original example — It doesn’t matter what the button looks likes, I just care that the button is there and the same will apply to other components in my web app, so how can I share generic button styles across my web app?
Android has a nice approach to this problem. Most styles in an Android app are / can be defined in a similar fashion to a web page.
- Define styles on a view / element itself.
- Define styles in an external file and assign it to a particular view / element. In Android this is done by assigning the style on the view’s layout, on the web this is done via class names or ID’s.
The final technique for defining styles in Android, and a common way to make your styles maintainable for an app, is to define a level of styles that sits between the system defined styles and the styles defined on the view directly — It’s referred to as a “theme” for an Android app.
Applying this to the web, it’s the equivalent of having styles that get layered on top of the user agents styles before the pages / components styles get applied. In this case, my crude diagram would look more like this.
In this scenario a developer has the best of both worlds. A set of base styles are defined that are common across pages and components. Page specific styles are separate from the base and take priority. Component styles are encapsulated from page styles, inherit the base styles and it’s own styles take precedence, overriding the base styles if needed.
This is an idea for layering styles in a way that a developer can define styles across components and their page, without taking ultimate control away from the component author / vendor.










