Beginning of 2020, I was stunned hearing from a front-end developer CSS variables are now fully supported by all browsers (even Edge)! This implies we can start using CSS(3) variables within our Lightning Components on the Salesforce Platform!
Showcase: Curious in an example on how CSS variables can be applied? In a later article the focus is put on the application of CSS variables, including a demo and public repository.
What are CSS3 variables?
Like in Apex and Javascript one can now also define variables in CSS, avoiding duplicate (‘hard-coded’) values and therewith improve maintainability and readability.
:root{ --primary-colour: #f15d22; } h1, h2, h3{ color: var( --primary-colour ); } button{ background: var( --primary-colour ); }
Variable definition
- Variables can be defined within any CSS Selector and are identified with the ‘
--
‘-prefix; - Variables are case-sensitive (!), implying
--myVar
!=--myvar
; - Variables follow the cascade policy and thus, each variable is available for all child elements;
- Variables can be overridden, but will only effect the children of the selector where it is overridden in. For adjacent and above positioned elements, the variable remains defined with the original value.
Variable retrieval
- A variable can be referenced by calling
var( [variableName], [fallbackValue] );
, where fallbackValue is optional; - The fallback value is applied, when the variable cannot be found, e.g. when the variable was defined outside the scope of the current selector;
- CSS Declarations are ignored when the variables returns empty, or makes no sense
(e.g.div{ color: var( --default-margin ); }
will be ignored).
Example: responsive design
Aside from being able to define colours in one central place, allowing to easily and consistently change the complete look and feel of your page (see first example above), there is one more use-case which gets me enthusiastic:
:root{ --content-margin: 2rem; } p{ margin: var( --content-margin ); } @media only screen and ( max-width: 420px ){ :root{ --content-margin: 1rem; } }
In the above code snippet you see another way to setup a websites’ responsive design. Instead of redefining all selectors within the @media-tag, the --content-margin
variable is changed, directly impacting all child-elements of the :root
-element which referencing it.
Update variables by Javascript
Comparable to all DOM element properties, CSS variables can also be retrieved, set and updated by Javascript. This allows one to conditionally update the look and feel of the website. E.g. on customer interaction (button click), or by Javascript validation, such as window size, browser, domain and such.
// get variable from inline style let curMargin = element.style.getPropertyValue( "--content-margin" ); // get variable from wherever getComputedStyle( element ).getPropertyValue( "--content-margin" ); // halve the current content-margin element.style.setProperty( "--content-margin", curMargin / 2 );
How to benefit in Lightning Web Components?
Next to the benefits of higher maintainability and easier to read styling, there is one more significant impact I fancy of using CSS Variables in Lightning Web Components: reusability of child components!
Definition Intermezzo:
By definition of online Web Components, Lightning Web Component have a Scoped CSS. This implies, CSS defined within the shadow DOM will not ‘leak outside’, nor will page styles bleed into it. Example: when in component A you set the body-background to pink, this only applies to the body of component A, not to any page that includes A.
Salesforce forces this by adding the name of the component to each of it’s DOM elements and also append this to all CSS selectors. The CSS, therefore, only applies to elements which satisfy the CSS selector AND contain the components’ name attribute (see code example below).
// ButtonComponent.html - Template file <div c-buttonComponent_buttonComponent class="custom-button" > [...] </div> // ButtonComponent.css - Stylesheet file .custom-button[c-buttonComponent_buttonComponent]{ background: blue; }
Because of this scoped CSS, LWC components strictly follow their own styling and are a bit harder to reuse. Imagine the button component in the snippet above, which you’d like to show on different pages/communities where different colour schemes are applied. Due to the scoped CSS you cannot ‘overrule’ the colour codes from the parent, and the button will always have a blue background. But… that is where CSS Variables come in!
Fortunately, CSS variables do come through within an Isolated DOM and therefore you can have your child-component shown in any way you’d like! The calling/parent component will set the variable, which the child component will show.
:host{ --background-colour: orange; }
.custom-button{ background: var( --background-colour, 'blue' ); }
Update May 27 – Reusable child components with default CSS Variable values
To make your child components really reusable, you don’t want to have them depend on the calling component providing the CSS variable or not. Unfortunately, I found the fallback value is only applied when an invalid value was retrieved. Luckily, there is a trick to get around this by using Javascript, as is shown below. A more detailed explanation of why and how this is working, can be found here.
_hasRendered = false; renderedCallback(){ if( !this._hasRendered ){ // Verify whether :host{} variables are inherited from the parent let computedStyles = window.getComputedStyle( this.template.host, null ); let accentColor = computedStyles.getPropertyValue( '--accent-color' ); // When accent color was not yet defined, define the variable if( !accentColor || accentColor.length == 0 ){ this.template.host.style.setProperty( '--accent-color', 'purple' ); } this._hasRendered = true; } }
Conclusion
CSS Variables allow you to:
- improve maintainability – colours are changed in only one spot;
- increase readability – one can easily see which margins are ‘related’, or which elements share the same colours (no need to compare hex-values 🙂 ) ;
- simplify LWC reusability – components can be setup flexibly to allow the parent to (optionally) define the styling. In case not defined, the fallback value is applied.
2 thoughts to “CSS variables in Lightning Components”
How to control only image height in lightning-carousel
How can I control only image style?
https://developer.salesforce.com/docs/component-library/bundle/lightning-carousel/example
Only the img height must be changed, not the header or description.
Thank You & Good Day : )
#Salesforce Developer #LWC Development
Hi @lakhan! Ah that’s a valid question. Checking in the browser I was able to impact the image height using
lightning-carousel-image img{ height: 50px; }
, though it might be that this is not possible when loading it in a LWC due to Locker Service. If so, and the height should really be modified I believe the only option is to not uselightning-carousel-image
but define the mark-up yourself, then you have full control. Hope this might help you!