How to Use CSS Variables for Colors in Web Design | Basics for Managing Color Palettes

TIPS

When the same colors are repeated throughout a website, changing the palette later can mean editing many separate declarations. CSS custom properties, commonly called “CSS variables,” let authors store a value under a name such as --color-primary and reuse it with var(). This article covers the basics of grouping background, text, and button colors into reusable variables, then applying them globally or overriding them within a specific component.

Start by grouping site-wide colors in :root

For colors shared across the whole site, defining custom properties on :root, which represents the document’s root element, makes them easy to reuse. For example, use white ■#FFFFFF for the main background, ■#F4F7F9 for supporting surfaces, ■#212529 for body text, ■#2C5B7A for the primary color, and ■#214660 for its hover state.

:root {
  --color-bg: rgb(255 255 255);
  --color-surface: rgb(244 247 249);
  --color-text: rgb(33 37 41);
  --color-primary: rgb(44 91 122);
  --color-primary-hover: rgb(33 70 96);
  --color-on-primary: rgb(255 255 255);
}

Custom property names begin with --, and you reference them where needed with syntax such as var(--color-text). CSS does not assign these names for you, so names based on purpose—such as primary, text, or surface—are usually easier to maintain than names based only on appearance, such as blue.

Assign variables to backgrounds, text, and buttons

1. Keep body text and background colors in separate variables

body {
  background: var(--color-bg);
  color: var(--color-text);
}

.card {
  background: var(--color-surface);
  color: var(--color-text);
}

Body text ■#212529 against white ■#FFFFFF has a contrast ratio—the relative brightness difference between foreground and background colors—of about 15.43:1. Against the supporting surface ■#F4F7F9, it is about 14.34:1. Keeping text and background in separate variables makes it clear which role has changed even when the same text color is reused on several surfaces.

2. Manage button background and button text separately

.button {
  background: var(--color-primary);
  color: var(--color-on-primary);
}

.button:hover {
  background: var(--color-primary-hover);
}

White ■#FFFFFF on the primary color ■#2C5B7A has a contrast ratio of about 7.28:1. On the hover color ■#214660, the ratio is about 9.95:1. Separating the button background from the text-on-button variable makes it easier to re-check the pair whenever the primary color changes.

3. Override values only inside a specific component

Custom properties defined with the standard -- syntax participate in the cascade and inherit from parent elements. That means you can override a value within one part of the page without changing the site-wide definition.

.card--dark {
  --color-surface: rgb(33 37 41);
  --color-text: rgb(255 255 255);
}

Inside this component, the surface becomes ■#212529 and the text becomes white ■#FFFFFF, with a contrast ratio of about 15.43:1. This is useful when a single component needs a darker theme while the rest of the site keeps the original values.

Do not assume a variable name makes a color combination accessible

A name such as --color-primary or --color-border does not automatically make the color readable or suitable for its role. For example, if a control border uses ■#758995 against white ■#FFFFFF, their contrast ratio is about 3.64:1. WCAG (Web Content Accessibility Guidelines) 2.2 requires at least 3:1 contrast against adjacent colors for visual information needed to identify user interface components, and at least 4.5:1 for normal-size text.

CSS variables make it easier to centralize changes, but after changing a value you still need to re-check the real combinations used for body text, button text, borders, and other adjacent colors. In HueRoll, you can enter a six-digit HEX code and review related colors, palette suggestions, and the selected color’s contrast against white or black. HueRoll does not compare arbitrary color pairs or automatically determine WCAG AA or AAA conformance, so contrast between CSS variables must be checked separately.