Theming with CSS Custom Properties (variables) and calc()

(Yes, that happens.

) Or if RGB and HSL is used in a mix?The other thing is that if a theme is added, you probably need to update the CSS for the individual components as well, and this introduces hard coupling within the system.

Step 2, Naive theming with custom propertiesSo to start with, you could use custom properties to ensure that the same value is used where it should be, and that it could be changed from somewhere central:Here you at least make sure that you safely can update colors and DRY.

But you still need to handle the coupling.

To do that, you could avoid using properties that are named after their values, and for example use a named color scheme as part of your system.

A color scheme could be something like primary and secondary color, or theme color and brand color, or something.

That is up to you.

Step 3, Not so naive theming with custom propertiesSo instead of referencing a custom property for a specific color, the components reference a named custom property from the color scheme, and this again can be changed from somewhere central without bothering the component.

And adding themes will be a breeze:Here the component references the propert –themecolor, and the value of that property is kind of set and scoped by the theme-class.

The added benefit is readability, since you now communicate the intent or role of the property.

You can still use custom properties for named values in addition.

And that would probably be good practice, since it reduces the risk of accidentally breaking the theming while adding and changing stuff.

You just assign the named value-property to the schemed-property:–themecolor: var(–purple);Step 4, Co-variation with calc()All well so far, but what about co-variation?.The thing is that custom properties can be used together with calc().

A usecase could be a top and side margin that need to be in a certain ratio:–marginSides: 30px;–marginTopBottom: calc(var(–marginSides) * .

7)If you change –marginSides, the marginTopBottom will follow.

So by using calc(), you can have co-variation in your system without pre-processors like LESS and SASS.

And this also goes for colors.

My favorite LESS color function is darken(), and, well, could we do something like that in plain CSS?.Yes, of course, and the secret to that is using HSL instead of RGB.

HSL is great because it separate the color into properties that are easier to manipulate than RGB, and each of those colors can be represented by custom properties:–hue: 255;–saturation: 100%;–lumnosity: 87%;–themecolor: hsla(var(–hue), var(–saturation), var(–lumnosity),1);And this could be used for theming and co-variation between color values, like a slighly darker border for some background color:Darkening of a color can be done by changing saturation and lumnosity using calc(), and in that way co-variation of shades can be handled by the system.

You need 50 shades?.No problem!And, as you can see in this Pen, a nice touch is that you also can use custom properties for shorthand properties, which greatly reduces the risk of accidentally introducing variability within the system:–themeBorder: var(–borderSize) solid var(–darkThemecolor);border: var(–themeBorder);You can still overwrite specific properties within the components if you need:.

cracyButton { border: var(–themeBorder); border-left: 15px dotted var(–cracyColor);}Step 5, Make sure that rules are calculated as they shouldCustom properties are scoped to the element(s) they are declared on, and participate in the cascade: the value of such a custom property is that from the declaration decided by the cascading algorithm.

https://developer.

mozilla.

org/en-US/docs/Web/CSS/–*The trick to using custom properties and calc() with theming, is that a CSS rule is not automatically updated if a property is changed, so if a property used in calc() is changed, you have to make sure that the rule is recalculated.

So something like this won’t work, since changing the property down in the DOM-tree does not automatically affect the .

themed-rule higher up://Does not work.

themed { –hue: var(–basichue); –themecolor: hsla(calc(var(–hue), .

);}.

procolTheme { –hue: var(–aWhiterShadeOfPale);}.

hendrixTheme { –hue: var(–purpleHaze);}<main class="themed"> <section class="procolTheme">.

</section> <section class="hendrixTheme">.

</section></main>Changing the order, or having them on the same node, as in the Pen, will help.

In addition there are possible strategies for forcing a recalculation of the calculating rule.

The basic principle is to do something that updates the property within the scope.

You could add a rule later in the flow that partly updates the rule.

If the usecase is theme per route, you can have a shared CSS with basic theming, and a per route CSS that overwrites the rule with just the needed properties.

Or the overwriting CSS can be in the components if routing is handled by the framework, or if you just need to handle different themes within the application for another reason.

It is also possible to add the overwriting rule by JavaScript.

If the usecase is dark-/lightmode and the browsers at that point all supports the media query prefers-color-scheme , you can trigger recalculation within the media query:@media (prefers-color-scheme: dark) { .

themed { –hue: var(–backInBlack); }}And as a sidenote here: Custom properties and media queries are great for handling responsive design in a theming system, since you can really minimize the needed code within the queries!Step 6, Over the topThe last one is more experimental than practical, but shows that you can implement a colorwheel-based colorscheme as co-variation.

But your designers will probably not thank you for it, since it misses the finetuning that make their day.

The scheme used in this Pen, is known as complementary split:Complimentary split: http://www.

paletton.

com/wiki/index.

php?title=Split_complementary_color_schemeSince hue can be seen as an angle in the color wheel (0–360 degrees), it is easy to derive the other colors in the scheme in the same way that you can manipulate saturation and lumnosity:–primaryHue: var(–hueBasic);–secondaryHue: calc(var(–primaryHue) + 150);–complementaryHue: calc(var(–primaryHue) + 210);And don’t worry if you get values > 360, it just starts another round.

SummarySo to sum it up.

CSS custom properties and calc() can help you dealing with sameness, coupling and co-variation within a theming system.

Sameness, since custom properties can define values that need to be the same throughout the system.

Coupling, since custom properties can be defined by their role, not only as shorthand for their value.

Co-variation can be handled by a combination of custom properties and calc() to bind values together, since calc() can use custom properties as parameters.

.

. More details

Leave a Reply