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.

With `ViewEncapsulation.Emulated`, styles defined in the ancestor component don’t impact a descendant component.

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.

Globally set styles do impact components… but they are hard to change dynamically.

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.

With `ViewEncapsulation.Emulated`, global styles also don’t impact a descendant component.

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 the var() 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.

see the source: https://gist.github.com/sulco/6860711bd1f7d72344f317118a28ff4f

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:

  • You can play with the application here
  • See the source code on Github

Things to note:

  • All dinos have the default ViewEncapsulation.Emulated with an exception of T-Rex, who uses ViewEncapsulation.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:

This story is published in The Startup, Medium’s largest entrepreneurship publication followed by +386,297 people.

Subscribe to receive our top stories here.