One approach to theming that works is to have a component-per-theme with non-encapsulated styles (encapsulation: ViewEncapsulation.None). Such components have no HTML template markup, and their only purpose in life is to sit at or near the top of the application and get dynamically get turned on and off as the theme is changed.
A simple theme-switcher component with a dropdown selector might look like this:
Each theme component has the same class names in its corresponding styleUrl list. For a "red-on-green" theme:
And its inverse:
Placing this at the top of the demo application, you will see this the first time you open it:
The problem comes when you try to change it back. Turns out, you can't. That's because when a component with ViewEncapsulation.None first gets initialized, its styles get injected into the of the page, and they never go away. So in this case, the second component's styles are sitting last in the , and they permanently override the first component's, regardless of which one is "on". And the situation is made all the bleaker by the fact that the Angular-injected style tags don't have a "name" attribute or anything else that would help you, say, find and remove them.
The first step in my approach to address this issue is to augment the CSS for each theme with a dummy class that uniquely identifies it. For the red-on-green theme:
Now, with a bit of DOM-programming determination, we can manipulate the style nodes in the head to get the effect that we want. I wrapped a quick-and-dirty implementation in an Angular service:
This apply() method of this service surfs the document's styleSheets looking for the one whose 0th rule matches the given theme name. Then it removes the corresponding node and re-appends it, thus making it appear last and giving it the winning set of class definitions. Each theme component then injects this service and calls apply() passing the theme name in ngAfterViewInit. For example:
Ideally, Angular would support this scenario better. Perhaps Material themes (which are now kind-of limited to colors) will expand to address more complete CSS re-theming of Angular applications.