CSS colour variables generator
--brand: #5b8def;--ink: #0f172a;--radius: 8px;--space: 16px;Generated in your browser · nothing is uploaded
Turns a list of name-and-value pairs into a :root block of CSS custom properties, normalising the names to valid identifiers and taking an optional prefix.
How to use the css colour variables generator
Custom properties are not Sass variables under a different name, and the difference is the whole reason to reach for them. A Sass variable is substituted at build time and then no longer exists; the browser never sees it. A custom property is a live value in the cascade. It inherits down the tree, so redefining --surface on one section restyles everything inside it. It can be read and written from JavaScript with getPropertyValue and setProperty. It can be redefined inside a media query, a container query or a [data-theme] attribute selector. A dark mode built on custom properties is a dozen redefined values rather than a duplicated stylesheet, and that is a consequence of the cascade rather than a trick.
Name them for their role and not their appearance. --brand-blue becomes a lie the first time the brand stops being blue, while --brand simply keeps working. The same argument separates --grey-100 from --surface: one describes what the value is and the other describes the job it does, and only the second survives a redesign. A useful compromise on a large system is two layers, a small set of raw values named for what they are and a set of role names pointing at them, so --surface: var(--grey-100) is the only line that changes when the palette shifts.
Two mechanical details are worth having straight. Custom property names are case-sensitive, so --Brand and --brand are genuinely two different properties, and this generator lowercases every name it writes. If your palette arrives in title case, the output is the version to use throughout, because a var(--Brand) elsewhere in the stylesheet will not find it. Anything that is not a letter, digit or hyphen becomes a hyphen, a leading -- you paste in is stripped rather than doubled, and a line with no colon or equals sign is split at its last space, so Brand Primary #f00 comes out as --brand-primary: #f00.
The failure mode to recognise is a rule that looks like it vanished. A normal invalid declaration is thrown away at parse time and the previous cascade value survives. A declaration containing var() cannot be checked that early, because the substitution happens later, so an invalid result is only discovered afterwards. At that point the property does not fall back to what it was: it becomes invalid at computed-value time and takes its inherited value if it inherits, or its initial value if it does not. Supplying a fallback inside the function, as var(--brand, #333), is how you keep control of that.
What people use it for
- Turning a palette handed over as a list of names and hex codes into a stylesheet
- Renaming value-based tokens to role-based ones in one pass
- Setting up the names a dark mode will redefine later
- Adding a project prefix to every custom property at once
- Getting a designer’s colour list into code without retyping it
Questions
Sass variables are substituted at build time and never reach the browser. Custom properties are live in the cascade: they inherit, they can be changed at runtime from JavaScript, and they can be redefined inside a media query.
For their role rather than their value. Names like --surface and --brand survive a redesign; --brand-blue and --grey-100 become misleading the moment the palette moves.
Because this normalises them, and it matters: custom property names are case-sensitive, so --Brand and --brand are two separate properties. Use the lowercase names it produces consistently throughout the stylesheet.
A colon or an equals sign is treated as an explicit separator. Without one it splits at the last space, so a multi-word name stays intact and Brand Primary #f00 becomes --brand-primary: #f00.
At the top of the stylesheet, before anything that uses it. The :root selector matches the html element, so every element on the page inherits from it.
Redefine the same names inside a prefers-color-scheme media query, or under a [data-theme="dark"] selector if you want a manual toggle. Nothing that consumes them has to change at all.
A declaration using var() cannot be validated at parse time, so an invalid substituted value is found too late to fall back the usual way. The property becomes invalid at computed-value time and takes its inherited or initial value instead. A fallback inside the function, var(--brand, #333), avoids it.