Theming Angular
Breaking through ViewEncapsulation to colour some dinos
Angular components have this interesting behaviour called ViewEncapsulation — it makes style defined for a component limited in scope to only that specific component. Depending on its setting, overriding these styles though can be tricky though. How then we can go about theming Angular applications?
The problem
Say you have a TrexComponent
and define its styles in trex.component.scss
file. Thanks to the ViewEncapsulation.Emulated
(which is set by default) these styles won’t impact any other part of your application.
But it works the other way around too: if, say, your root AppComponent
defines some styles, they won’t be applied to the child components.
You can set a global style in the global styles file (usually src/styles.scss
), but then it is set for all the components within the app, and more importantly, you can’t do it dynamically, e.g. when loading some user preferences and wanting to change a style based on that.
This issue of impacting the component’s style is even more apparent in the case of setting Native
(now deprecated) or ShadowDom
encapsulation. Because is “hides” the component behind a Shadow Root, even the global styles won’t affect your component.
Even if you don’t use ViewEncapsulation.ShadowDom
in your typical app, it’s a must once you want to create a reusable Web Component — so it really is an issue we need to learn how to solve.
The solution
To deal with this, we are going to use CSS Custom Properties, a.k.a. CSS variables.
Property names that are prefixed with
--
, like--example-name
, represent custom properties that contain a value that can be used in other declarations using thevar()
function.
What it means is that you define a custom property the same way as you would a normal css property, e.g. "font-size: 16px"
and it’s available to be referenced everywhere within the cascade (in the whole subtree of element that matched the selector you’ve used when defining the property.)
Now, if you haven’t work with css custom properties before it takes a while to sink in (speaking from experience…), but it’s an extremely powerful tool.The important thing is not to think of them as an alternative to SASS, or Less variables — these are only calculated during compilation, so they’re static. Instead treat them as you would any other CSS property (think: font-size
).
So you can, for instance:
- set different values in different components (“GreenDinosComponent” vs “PinkDinosComponent”),
- change them with pseudo-classes (
:hover {--main-color: darkgreen}
) - …or with media queries
- and, finally, set them dynamically with a custom directive!
A simple directive such as the one below should be enough.
One thing to note is that [ngStyle]="{....}"
type of bindings won’t work as for now — see the discussion in this Github issue — so a custom directive like this is one of the possible workarounds.
Demo application
Ok, so I’ve shown you some illustrations, some code snippets, but how to put that together? Does it actually work? :-) Well, see for yourself:
Things to note:
- All dinos have the default
ViewEncapsulation.Emulated
with an exception of T-Rex, who usesViewEncapsulation.ShadowDom
— so you can see the theming working for both cases. - You don’t actually have to put the custom properties
[dtTheme]
directly on a component, it can be applied on any HTML element in your app. The theme will be applied to everything inside:
<div [dtTheme]="getCustomTheme()">
<dt-ptero></dt-ptero>
<dt-trex></dt-trex>
</div>
- I’m using both custom CSS properties and SASS variables there. Yes, nothing prevents you from using both, actually it often makes a lot of sense (see the next “epilogue section”)
- Custom Properties are supported in all current browsers (no IE then, see the compatibility table).
Epilogue
So now that you have a great case to use custom properties you might wonder: do we still need things like SASS variables? And if the answer is yes, then when to use which method of storing CSS values?
The general answer is:
- use SASS/Less when you need to set values statically, when you need to perform some operations (e.g.
`$color2 = lighten($mycolor)
) during compilation of your application. Use is to customise your general css structures. To tailor-make your Bootstrap/Foundation/etc. to your needs. - use custom properties when you need to change values dynamically, e.g. have infinite color combinations to setup by your users. Use them when you need this theming capability for components :)
If you still have any doubts, take a look at this fantastic article on Smashing Magazine.
And, as usual: if you’ve learned something new, please:
→ clap 👏 button below️ so more people can see this
→ follow me on Twitter (@sulco) so you won’t miss future posts: