Using CSS Variables for fast and easy design variations
Tags: css, design, variables
Published: 2020-08-23 01:35:02

CSS Variables can allow you to make better and easier to maintain design decisions using plain vanilla CSS. 

The following code will be using a React custom button component, but this will work anywhere you can define CSS Variables

Starting off in our index.css, we will define the following styles:

```
html {
  --s: .5rem;
  --m: 1rem;
  --l: 1.5rem;
  --xl: 2rem;
  --xxl: 2.5rem;
  --xxxl: 3rem;
  --primary-background: #f0f0f0;
  --main-color: 230;

  box-sizing: border-box;
  font-size: 16px;
  margin: 0;
  padding: 0 2rem;
  background-color: var(--primary-background);
}

button + button {
  margin-left: var(--m);
}
```

The styles declared in the `html` element are part CSS reset, and part defining some variables I will use throughout the app. The `rem` variables will not be the focus, but are a convenient system for me to size certain elements. 

The `button + button` line will apply a left-margin to the second button if there are two buttons placed side by side. 

My Button component is simple and minimal:

```
import React from "react";
import "../styles/Button.css";

function Button({ text, type }) {
  return (
    <button className={type}>
      {text}
    </button>
  );
}

export default Button;
```

Here I'm importing some custom styles and adding using the prop `type` that gets added as a class to the button element. 

The `../styles/Button.css` module for this component is as follows:

```
button {
    --main-color: 230;
    --border-size: 1.5px;
    --saturation: 80%;
    --lightness: 55%;

    border-radius: var(--s);
    padding: var(--s) var(--xl);
    font-weight: 800;
    font-size: var(--m);
    margin: .5rem;
    min-width: 10rem;
}

.alert {
    --main-color: 360;
}

.confirm {
    --main-color: 150;
    --saturation: 90%;
    --lightness: 40%;
}

.info {
    --main-color: 190;
    --saturation: 85%;
    --lightness: 50%;
}

.primary {
    background-color: hsl(var(--main-color), var(--saturation), var(--lightness));
    color: var(--primary-background);
    border: var(--border-size) solid hsl(var(--main-color), var(--saturation), var(--lightness));
}

.secondary {
    background-color: var(--primary-background);
    color: hsl(var(--main-color), var(--saturation), var(--lightness));
    border: var(--border-size) solid hsl(var(--main-color), var(--saturation), var(--lightness));
    font-weight: 700;
}
```

Finally, my App component:

```
import React from "react";
import Button from "./components/Button.jsx";

function App() {
  return (
    <>
      <div>
        <Button text="Submit" type="primary" />
        <Button text="Cancel" type="secondary" />
      </div>
      <div>
        <Button text="Delete" type="primary alert" />
        <Button text="Cancel" type="secondary alert" />
      </div>
      <div>
        <Button text="Accept" type="primary confirm" />
        <Button text="Cancel" type="secondary confirm" />
      </div>
      <div>
        <Button text="OK!" type="primary info" />
        <Button text="More Info" type="secondary info" />
      </div>
    </>
  );
}

export default App;
```

This renders the following 8 buttons in our browser:
![App component with 8 variations of the Button component](https://i.imgur.com/9PXJEuK.png)

Let's take a look and unpack what is happening here. 

Looking at our first 4 buttons again in the App component,

```
[...]
      <div>
        <Button text="Submit" type="primary" />
        <Button text="Cancel" type="secondary" />
      </div>
      <div>
        <Button text="Delete" type="primary alert" />
        <Button text="Cancel" type="secondary alert" />
      </div>
[...]
```

We can see that we are passing in 'primary' and 'secondary' as the main variations of our Button component. On the bottom two Buttons, we are passing in an additional class, 'alert' as well. 

Here is what some of our Button component's CSS looks like again:

```
button {
    --main-color: 230;
    --border-size: 1.5px;
    --saturation: 80%;
    --lightness: 55%;

    border-radius: var(--s);
    padding: var(--s) var(--xl);
    font-weight: 800;
    font-size: var(--m);
    margin: .5rem;
    min-width: 10rem;
}

.alert {
    --main-color: 360;
}

[...]

.primary {
    background-color: hsl(var(--main-color), var(--saturation), var(--lightness));
    color: var(--primary-background);
    border: var(--border-size) solid hsl(var(--main-color), var(--saturation), var(--lightness));
}

.secondary {
    background-color: var(--primary-background);
    color: hsl(var(--main-color), var(--saturation), var(--lightness));
    border: var(--border-size) solid hsl(var(--main-color), var(--saturation), var(--lightness));
    font-weight: 700;
}
```

We are using inverted colour schemes for our primary and secondary Button backgrounds and text colours, and making use of our CSS variables to define those colours. 

The interested part here is specifically the `.alert` class that is redefining the `--main-color` variable to a different value. Attaching just the 'alert' class to the Button component will change its colour in an easily maintainable way.

We can do the same thing for other variations we would like to use in our application. The other classes I use to change the values and apply new colours are:

```
.confirm {
    --main-color: 150;
    --saturation: 90%;
    --lightness: 40%;
}

.info {
    --main-color: 190;
    --saturation: 85%;
    --lightness: 50%;
}
```

These are easily applied to the other 4 buttons just like before:

```
[...]
      <div>
        <Button text="Accept" type="primary confirm" />
        <Button text="Cancel" type="secondary confirm" />
      </div>
      <div>
        <Button text="OK!" type="primary info" />
        <Button text="More Info" type="secondary info" />
      </div>
[...]
```
Adding more variations or changing the colours is as simple as changing a single value in our Button.css module.

If I wanted to change the `info` class to a different colour, I can make a simple adjustment to the CSS for `.info`:

```
.info {
    --main-color: 270; // Value changed from 190 to 270
    --saturation: 85%;
    --lightness: 50%;
}
```
Previously, my `info` class Buttons looked like:
![info Button old](https://i.imgur.com/p0vfTGl.png)

And now with a single value change, it looks like:
![info Button new](https://i.imgur.com/KUox6lf.png)

Using CSS Variables opens up a lot of nice solutions to problems we see when designing out own interfaces.

![App component with 8 variations of the Button component, updated last 2 buttons](https://i.imgur.com/ICLUdmq.png)