DEV Community

Jordan Rowland
Jordan Rowland

Posted on

Using CSS Variables for fast and easy design variations

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);
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

This renders the following 8 buttons in our browser:
App component with 8 variations of the Button component

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>
[...]
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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%;
}
Enter fullscreen mode Exit fullscreen mode

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>
[...]
Enter fullscreen mode Exit fullscreen mode

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%;
}
Enter fullscreen mode Exit fullscreen mode

Previously, my info class Buttons looked like:
info Button old

And now with a single value change, it looks like:
info Button new

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

Top comments (1)

Collapse
 
mustafaaljassim profile image
Eng_Mustafa

CSS variables are awesome, and it can definitely give you more control over your design. Thanks for sharing!