As a front-end developer, I’ve been fairly interested in how different individuals code up their web sites. So I are likely to poke my head into design methods every time I discover one.
Then, late final 12 months, a dialog with Geoff Graham set me off pondering even deeper about theming web sites. (In case you don’t know that dude, he’s the chief editor of this web site, in order that man’s a reasonably large deal, too.)
So I’ve been watching, pondering, and exploring:
- How can we create higher themes?
- How can we enable elevated flexibility in theming?
- How can we enable extra colours for use in order that websites will be extra alive and dimensional as a substitute of being so flat on a regular basis?
Immediately, I wish to focus on a few patterns that the neighborhood is utilizing, and the way I suggest we are able to enhance, so we obtain each flexibility and wonder.
Hope you’re able to go on a wild experience with me!
Coloration Palettes
Let’s start from the start. In any case, how are you going to focus on theming with out together with colours into the location?
I believe this downside is just about solved by now. Everybody has adopted methods that enables for numerous hues — together with a number of tints and shades — that can provide some life to the design.
We don’t have to go very far to see this pattern occurring. For instance, Tailwind CSS features a ton of colours and their respective tones.

Open Props by Adam Argyle supplies much more tones, as much as 13 per shade.

And Pico CSS ups the ante by introducing 19 totally different tones per shade.

Er… this isn’t a race, so the variety of tones doesn’t actually matter. What’s vital is you get adequate shade tones to create delicate results for numerous components of the design.
Designing Your Personal Palette
Coloration palettes offered by these libraries and frameworks will be good beginning factors, however I’d argue that you just nearly by no means wish to use them.
Why?
As a result of colours create differentiation; differentiation creates distinction; distinction creates id.
You most likely know that is true with out me telling you.
- Websites that use Bootstrap, seem like Bootstrap.
- Websites that use Tailwind, seem like Tailwind.
- Websites that use shadcn, seem like that too…
In fact there are makers who can break the mould, use Tailwind, and make it fully not like Tailwind. However that’s as a result of they tweak many issues.
Coloration is certainly one of this stuff — one of the crucial vital ones — however different vital items embody typography, spacing, the roundness of your corners… and lots of others. Overlaying these is a narrative for an additional day, and maybe greatest lined by Jack McDade who teaches Radical Design.
So, in the event you don’t wanna drown within the sea of sameness — trying like everybody else — creating your personal shade palettes is a primary step ahead.
Now, chances are you’ll be concerned about creating shade palettes as a result of there’s been numerous writing in regards to the quantity of labor that goes into creating accessible shade palettes, so which may sound like a frightening job.
Plus, something associated to accessibility carries “Huge Potential Penalties” and “Extremely Shameful When Accomplished Incorrectly,” so that may add additional strain on you.
Throw all these pressures away.
Don’t be scared.
As a result of if you wish to create a nook of the web that appears such as you (or your organization), breathes such as you, acts such as you, and exudes enjoyable such as you do, then gotta do what you gotta do.
There are solely two phrases you must keep in mind.
Simply two phrases.
Adequate distinction.
And also you’re set for accessibility (design-wise, no less than).
That’s it.
Designing Coloration Palettes by Hand
I are likely to design shade palettes by hand — in Figma — after I design my web sites. This appears to be probably the most pure course of for me. (Or possibly I’m simply influenced by how Jack designs stuff 🙃).
In case you do that, there’s no have to stress about filling up tones from 50 to 950. That’s since you’ll do not know what colours would look good earlier than you match them into the design. Stressing over tones is placing the cart earlier than the horse.
Right here’s a good instance. After I designed Splendid Labz, I omitted a ton of shade tones. Right here’s an instance of the pink shade variables for the location.
- Discover I skipped values between 50 and 400? Nicely, I didn’t want ’em.
- Discover I added
200d
and600d
? Nicely, I kinda wished a desaturated (or muted) variant of those colours… which… couldn’t be captured the present methods. So I addedd
for desaturated 🙃.
You possibly can see the outcomes of that your self. It’s not too shabby for my part — with splashes of shade that maybe deliver some pleasure to your face whenever you scroll by the location.

You get the drift, yeah? It’s not too laborious. So, don’t be scared and provides {that a} strive.
Designing Coloration Palettes Programmatically
In case you’re the kinda person who prefers producing colours programmatically (and naturally you’ll be able to hand-tweak them afterwards in the event you want), listed here are just a few mills chances are you’ll fancy:
Of those, I extremely advocate testing @meodai‘s RampenSau as a result of he’s actually educated in regards to the shade area and does unbelievable work there. (Use the monochromatic function to make this simple.)
🎉 Simply launched RampenSau v1.0.0 on npm and GitHub! 🎢🐷
After some Easter weekend coding, the colour palette era library is now steady with improved docs and APIs.
Generate lovely shade ramps on your knowledge viz, design work, or generative artwork!
meodai.github.io/rampensau/
— David Aerne (@meodai.bsky.social) April 21, 2025 at 3:55 PM
Utilizing the Coloration Palettes
A thousand phrases later, we’re lastly attending to the meat of this text. 😅
With a seemingly limitless quantity of choices given by the colour palettes, it is sensible to imagine that we are able to use them nonetheless we would like — however in relation to software, most methods appear to fall quick.
(Even quick is beneficiant. They really appear to be severely restricted.)
For instance, DaisyUI appears to assist solely two tones per shade…

Pico CSS, a system with one of the crucial choices, on first look, limits to 10 potential variants “semantic class names“.

However in the event you look deeper, we’re nonetheless taking a look at about two tones per “factor”:
- Major (one tone)
- Background and background hover (two tones)
- Border and border hover (two tone)
- Underline (is that this the identical as border? Extra on this beneath.)
- And so forth…
Which brings me to at least one crucial and really puzzling query:
If colours are so vital, why do these frameworks enable solely the utilization of so few colours?
I can’t reply this query as a result of I’m not the creators behind these methods, however I’d guess these is likely to be the potential causes:
- These system designers may not be as delicate to colours as visible designers.
- Semantic class identify confusion.
- Values had been merely meant as tips.
The second a severe, and limiting, difficulty that we are able to take care of right now.
As for the primary, I’m not saying I’m a fantastic designer. I’m merely saying that, with what I do know and have found, one thing appears to be amiss right here.
Anyway, let’s speak in regards to the second level.
Semantic Class Title Confusion
Observing the “semantic class names” these methods use really unveil underlying confusion about what “semantic” means to the online growth neighborhood.
Let’s return to my comment in regards to the --pico-primary-underline
variable earlier with Pico CSS.
However in the event you look deeper, we’re nonetheless taking a look at about two tones per “factor”
- Major (one tone)
- Background and background hover (two tones)
- Border and border hover (two tones)
- Underline (is that this the identical as border? Extra on this beneath)
- And so forth…
Isn’t that an fascinating comment? (I ask this query as a result of underline
and border
can use the identical shade to create a unifying impact).
From what we are able to see right here, the time period “semantic” really means two issues conflated into one:
- An order of hierarchy (
main
,secondary
,tertiary
, and so on) - The “factor” it was imagined to fashion
This will get much more complicated as a result of the order of hierarchy can now be cut up into two components:
- A color-specific order (so
main
meanspurple
,secondary
meansblue
, and so forth) - A use-case particular order (so a
heavy
button is likely to bemain
, whereas amild
button is likely to besecondary
)

Okay. I can hear you say “naming is tough.” Sure, that’s the widespread grievance. However “naming is tough” as a result of we conflate and cut back issues with out making distinctions.
I suggest that:
- We preserve the hierarchy (
main
,secondary
,tertiary
) to the colour hue. - We identify the energy, “oomph,” or weight of the button with a verb that describes their relative weight or look, like
define
,mild
,heavy
,ghost
, and so on.

We are able to create the looks variations simply with one thing I name The Pigment System. However maybe that’s an article for an additional day.
Anyway, by creating this separation, we are able to now create a wealth quantity of shade mixtures with out being restricted by a single hierarchical dimension.
Shifting on…
The Second Drawback With Semantics
Utilizing the identical instance (only for simplicity, and undoubtedly not making an attempt to bash Pico CSS as a result of I believe they’re doing a very good job in their very own proper), we see that semantics are conflated by stating its hierarchy alongside what its imagined to fashion.
Examples are:
--pico-primary-background
--pico-primary-border
These two properties lead to an issue when designing and growing the location later. In case you contemplate these questions, you’d see the issues too:
First: Through the use of --pico-primary-background
…
- Does it imply we solely have one essential background shade?
- What if we want different colours? Can we use
--pico-secondary-background
? - What if we want extra? Can we use
tertiary
(third),quaternary
(4th),quinary
(fifth), andsenary
(sixth) for different colours?
Second: What if we’ve variants of the identical shade? Can we use issues like --pico-primary-background-1
, 2
, 3
, and so forth?
Third: Now, what if I would like the identical shade for the --pico-primary-background
and the --pico-primary-border
of the identical element? However I’d want one other shade for a second one?
This begins getting complicated and “semantics” begins to lose its that means.
What Semantics Truly Imply
Consulting Etymology and the dictionary provides us clues about find out how to really be semantic — and preserve that means.


Two issues we are able to see right here:
- Semantics imply to point by an indication.
- It may be associated to that means or logic.
What I’m noticing is that individuals usually ascribe “semantics” to phrases, as if solely phrases can convey meanings and numbers can not…
However what if we broaden our scope and think about numbers as semantic too — since we all know 100 is a a lot lighter tint and 900 is a darkish shade, isn’t that semantics exhibiting by numbers?
Higher Semantics
We have already got a superbly usable semantic system — utilizing numbers — by the colour palettes.

What we merely want is to regulate it such that we are able to use the system to simply theme something.
How? Easy.
I made the argument above that the hierarchy (main
, secondary
, and so on.) needs to be used to consult with the colours.
- Then, if in case you have use
pink
shade as your essential (thereforemain
) shade… - You possibly can merely set one other shade, say
orange
as yoursecondary
shade!
(Duh? Yeah, it’s apparent in hindsight.)
Implementing this into our code, we are able to do a one-to-one port between hierarchy and hues. In case you do that by way of CSS, it may be handbook and never very enjoyable…
.theme-pink {
--color-primary-100: var(--color-pink-100);
--color-primary-200: var(--color-pink-200);
--color-primary-300: var(--color-pink-300);
/* and so forth ...*/
--color-secondary-100: var(--color-orange-100);
--color-secondary-200: var(--color-orange-200);
--color-secondary-300: var(--color-orange-300);
/* and so forth ...*/
}
With Sass, you’ll be able to run a fast loop and also you’ll get these values shortly.
$themes: (
pink: (
main: pink,
secondary: orange
)
);
$color-tones: 100, 200, 300, 400, 500, 600, 700, 800, 900;
@every $theme-name, $theme-colors in $themes {
.theme-#{$theme-name} {
@every $tone in $color-tones {
--color-primary-#{$tone}: var(--color-#{map-get($theme-colors, main)}-#{$tone});
--color-secondary-#{$tone}: var(--color-#{map-get($theme-colors, secondary)}-#{$tone});
}
}
}
For Tailwind customers, you possibly can do a loop by way of a Tailwind plugin in v3, however I’m not fairly certain how you’ll do that in v4.
// The plugin code
const plugin = require('tailwindcss/plugin')
module.exports = plugin(perform ({ addUtilities, theme }) {
const splendidThemes = theme('splendidThemes', {})
const palette = theme('colours')
// Gather all distinctive tone keys utilized by any shade in any theme
const allTones = new Set()
Object.values(splendidThemes).forEach(themeConfig => {
Object.values(themeConfig).forEach(colorName => {
if (palette[colorName]) {
Object.keys(palette[colorName]).forEach(tone => allTones.add(tone))
}
})
})
const utilities = {}
Object.entries(splendidThemes).forEach(([themeName, themeConfig]) => {
const themeClass = {}
Object.entries(themeConfig).forEach(([role, colorName]) => {
if (!palette[colorName]) return
allTones.forEach(tone => {
if (palette[colorName][tone] !== undefined) {
themeClass[`--color-${role}-${tone}`] =
`var(--color-${colorName}-${tone})`
}
})
})
utilities[`.theme-${themeName}`] = themeClass
})
addUtilities(utilities)
})
// Utilizing it in Tailwind v3
module.exports = {
plugins: [
require('path-to-splendid-themes.js')
]
theme: {
splendidThemes: {
pink: {
main: 'pink',
secondary: 'orange'
},
blue: {
main: 'blue',
secondary: 'purple',
tertiary: 'orange'
}
}
},
}
Will this generate quite a lot of CSS variables?
Sure.
However will in have an effect on efficiency?
Perhaps, however I’d guess it received’t have an effect on efficiency a lot, since this code is simply a few bytes extra. (Photos, against this, weigh hundreds of occasions greater than these variables do.)
And now we not want to fret about realizing whether or not background-1
or background-2
is the proper key phrase. We are able to merely use the semantic numerals in our elements:
.card {
background-color: var(--color-primary-500)
}
.card-muted {
background-color: var(--color-primary-700);
}
One Extra Notice on Semantics
I believe most frameworks get it proper by creating component-level semantics. This makes a ton of sense.
For instance, with Pico CSS, you are able to do this:

In your personal creations, you would possibly wish to cut back the quantity of namespaces (so that you write much less code; it’s much less tedious, yeah?):
.card-namespaced {
--card-header-bg: var(--color-primary-600);
}
.card-without-namespace {
--header-bg: var(--color-primary-600);
}
No “additional semantics” and even “namespacing” wanted when the challenge doesn’t require it. Be at liberty to Hold It Easy and Candy.
This brings me to a separate level on element vs international variables.
International Variables
Some variables needs to be international as a result of they will propagate by everything of your web site with out you lifting a finger (that’s, when you design the CSS variables appropriately).
An instance of this with borders:
:root {
--border-width: 1px;
--border-style: strong;
--border-color: var(--color-neutral-700);
}
You possibly can change the worldwide --border-color
variable and modify every thing directly. Nice!
To make use of this sorta factor, you must construct your elements with these variables in thoughts.
.card {
border: var(--border-width) var(--border-style) var(--border-color);
}
This may be simply created with Tailwind utilities or Sass mixins. (Tailwind utilities will be handy Sass mixins).
@utility border-scaffold {
border: var(--border-width) var(--border-style) var(--border-color);
border-radius: var(--radius);
}
Then we are able to simply apply them to the element:
.card {
@apply border-scaffold;
}
To vary the theme of the cardboard, we are able to merely change the --border-color
variable, without having to incorporate the card-border
namespace.
.card-red {
--border-color: var(--color-red-500);
}
This fashion, authors get the flexibility to create a number of variations of the element with out having to repeat the namespace variable. (See, even the element namespace is pointless.)
.pico-card-red {
--pico-card-background-color: var(--color-red-500);
}
.card-red {
--bg-color: var(--color-red-500);
}
Now, I do know we’re speaking about colours and theming, and we segued into design methods and coding… however are you able to see that there’s a approach to create a system that makes styling a lot simpler and far more efficient?
Nicely, I’ve been pondering this kinda factor lots over at Splendid Labz, particularly in Splendid Kinds. Have a look in case you are .
Sufficient tooting my very own horn! Let’s return to theming!
I believe listed here are another values that you just would possibly wish to contemplate in your international variables:
:root {
--border-width: ...;
--border-style: ...;
--border-color: ...;
--outline-width: ...;
--outline-style: ...;
--outline-focus-color: ...;
--outline-offset: ...;
--transition-duration: ...;
--transition-delay: ...;
--transition-easing: ...;
}
How Essential is All of This?
It will depend on what you want.
Individuals who want a single theme can skip your entire dialog we hashed out above as a result of they will simply use the colour palettes and name it a day.
.card {
background: var(--color-pink-500);
shade: var(--color-pink-900);
}
For individuals who want a number of themes with a easy design, maybe the stuff that Pico CSS, DaisyUI, and different frameworks have offered is adequate.

Facet Rant: Discover that DaisyUI comprises variables for --color-success
and --color-danger
? Why? Isn’t it apparent and constant sufficient that you need to use --color-red
for errors straight in your code? Why create an pointless abstraction? And why topic your self to their limitations? Anyway, rant finish. You get my level.
For individuals who need flexibility and plenty of potential shade shades to play with, you’ll want a extra sturdy system just like the one I urged.
This entire factor jogs my memory of Jason’s Cohen’s article, “Uncommon issues turn into widespread at scale”: what’s okay at a decrease stage turns into not okay at a bigger scale.
So, take what you want. Enhance what you want to. And will this enable you by your growth journey.
In case you wanna take a look at what I’ve created for my design system, head over to Splendid Kinds. The documentation should be missing when this submit will get printed, however I’m making an attempt to finish that as quickly as I can.
And in the event you’re excited about the identical quantity of rigour I’ve described on this article — however utilized to CSS layouts — contemplate testing Splendid Layouts too. I haven’t been capable of look again after I began utilizing it.
Have enjoyable theming!