Table of Contents
CSS variables are often underutilized in favor of CSS-in-JS solutions. I work in a lot of styled-component and Emotion projects and I find myself reaching for CSS variables more and more.
CSS variables:
- Are scoped the an element and it’s children
- Work with the
calc()
function - Can be changed at runtime
Theming
import styled from "@emotion/styled";
import { variant } from "styled-system";
import * as Menu from "@radix-ui/react-menu";
const MenuItem = styled(Menu.Item)`
background: var(--background);
color: var(--color);
${({ theme }) =>
variant({
prop: "intent",
variants: {
"default:hover": {
"--color": theme.colors.grey900,
"--background": `${theme.colors.grey400}`,
},
"danger:hover": {
"--color": theme.colors.red800,
"--background": theme.colors.red100,
},
},
})}
`;
export function Menu() {
return (
<Menu.Root>
<Menu.Content>
<MenuItem>View Details</MenuItem>
<MenuItem>Add Record</MenuItem>
<Menu.Separator />
<MenuItem intent="danger">Delete</MenuItem>
</Menu.Content>
</Menu.Root>
);
}
In the above example, we are using the variant
function from styled-system
to create a button component that can be themed. Note how we map theme colors, named for their color, to CSS variables named for their user-facing intent.
Responsive Design
For scalable designs (e.g. graphics made with code) we can use calculations with CSS variables to properly scale children up and down without having to manually calculate the values.
This example uses BEM with SCSS, but the same concept applies to any CSS solution.
.card {
&__wrapper {
--card-padding: 1rem;
padding: var(--card-padding);
@media (min-width: 1200px) {
--card-padding: 1.625rem;
}
@media (min-width: 720px) {
--card-padding: 1.25rem;
}
}
&__main {
position: absolute;
top: var(--card-padding);
left: var(--card-padding);
width: calc(100% - (var(--card-padding) * 2));
height: calc(100% - (var(--card-padding) * 2));
}
}