Building Design Systems with CSS Variables
For organizations that have to design for multiple platforms, establishing a set of design standards and repeatable components (what we call Design Systems) is becoming increasingly important. In this article, we will break down how to create Design Systems with CSS Variables, a powerful browser API that helps developers create repeatable style components so that the organization’s brand and user experience remain consistent across products.
What is a CSS Variable?
It is important for us to understand the basics of the CSS properties set. There are two key points here: defining a custom property and using it with the var function inside your code.
The definition of a custom property is done inside any CSS selector. This must always be a key + value pair in the syntax of –name: value`.
Descendants of that selector will have access to the property and will be able to overwrite them.
We can add different types of values that are incredibly diverse, including numeric values, colors, and property values.
These values will always be passed untouched and indifferent to the intention of use. Let’s say you want to use the custom property weight as a height measurement. It will be invalid as size measurements require a unit, such as `px`, `rem`, etc…
You can attach them to a selector `:root`. This is a synonym for the HTML tag, so it will be globally available with a higher selector specificity.
Using CSS Variables
Using the custom property names as values in a CSS property will give you an error. To isolate the use of custom properties, we use the `var()` function, passing the property name as defined. CSS Variables are very robust, so we can mix this with other CSS functions such as `calc()`, `clamp()`, and as partial parts of a complete property.
What is a Design System?
Design systems are defined sets of guidelines and repeatable components that help developers simplify the creation of new components. Doing so helps development teams accomplish a consistent look and feel across products and gives way to enhanced creativity and productivity. This sounds great, but when implementing on the code side it can become messy for several reasons, including the huge number of values that can come from a Design System, the resulting need to keep track of them on your own, and tweaks you have to make during development. Even the simplest UI can lead to many small, sometimes noticeable discrepancies that can give the page an odd look. This is why design systems should not only include the ‘what’, but also the ‘how’ and ‘why.’
Creating a Design System using CSS Variables
The idea is that you shouldn’t have standalone values used in your CSS. Always (in the scope of sense) use variables instead. Let’s define a button with variables instead, so we don’t have values floating around:
We will keep only keywords and variables, this way we can tell this button is primary and has a regular size. Also, if for some reason we changed the variables, they will automatically update everywhere instead of having to find and replace each instance where the specific measure was used.
Some properties that are necessary to define for your system are:
- Font Size
- Border Radius
- Line Height
- Z Index
Doing this allows you to keep track of the different design options and allows you to see each of them and their corresponding values in the browser. In other words, you are using code as documentation.
An example of this is having named z-indices; this way we can tell how spinners should be over everything no matter what, and that overlays will hide the navs even if it has some importance. This also speaks about how the interactions should work.
For colors, intentions are more important than the actual values. This will become important because we will be able to override this and create themes, so ‘primary’ is a better name than ‘green’ for our button.
Automation & Extension
Current technologies also are aware of these situations and come with their own solutions. For this part, we’ll be using React to showcase the different approaches. But as CSS Variables are a web standard, this solution can also be applied to Vainilla, Svelte, Vue, and even pre-processors such as SASS.
CSS-in-JS for Automation
Although having all the different properties predefined can make a wonderful development experience, creating this experience from scratch can be overwhelming as we try to choose the right sizes and write them all into a gigantic base stylesheet. Now that we can create CSS dynamically, we can solve this by simply creating the sizes as a JS Object and parsing this into a globally available stylesheet.
This can be done in a few steps. First, define the values as an object. This will be important as we’ll be naming the values already in place and have techniques to iterate over objects. Second, we’ll create a function that parses that into valid custom properties. Finally, we’ll throw all of this in styled-components into a globally available stylesheet. See this gist with a complete implementation.
CSS Variables VS Theme Providers
Themes and Dark Mode
CSS Variables are defined in a global scope, allowing us to enable “Themes.” With these, the content on your site can be displayed in multiple palettes (think MySpace here) and allows you to detect and/or enable the option for the user to choose dark mode. This can be handled with classes and media queries. See the following examples:
Here, we use CSS only to determine that the user prefers a dark color schema. If that CSS media feature is not supported or the user prefers a light scheme, the default version of the website will be used. This can be used to extend any properties to those that fit the schema better.
It’s recommended that the default theme is the light one. In the case that something fails, a more natural experience is provided to the user.
Remember the importance of having a CSS Code that relies on these variables and keywords so it can update correctly.
Now imagine that you have not only defined a `dark` theme but also a `blueShades` or `pride` theme.
You can allow your user to choose and your work is simply to overwrite the intentions to values that match the desired theme.
Building a robust design system can help your organization create beautiful, harmonic, and reliable interfaces. Now that you understand the power and value behind creating your own design system using CSS Variables as its engine, it’s up to you what you want to create.