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:
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:
And now with a single value change, it looks like:
Using CSS Variables opens up a lot of nice solutions to problems we see when designing out own interfaces.
Top comments (1)
CSS variables are awesome, and it can definitely give you more control over your design. Thanks for sharing!