Intro
I’ve struggled with colors for a long time. Mainly because I believed what looked good to me, doesn’t necessarily look good to others and especially as a user interface. Color pallettes are subjective, it’s why different themes and colors are popular features in software.
How do I select a good color? How do I select it’s compliment? text? background? So many questions. Online tools like Realtime Colors helped a lot, and I continue to use them. However it’s not always a hit.
This document, like a few others Sajid’s Web Wisdom , is my summary of the things Sajid on YouTube says on the topic. Video link here.
What is needed
Four main color categories.
- Background
- Borders
- Text
- Primary/brand colors.
Backgrounds
For Backgrounds, you want neutrals. Preferably three shades of the background.
- Background
- Cards and containers
- Buttons and elements
Borders
Borders require a color that’s the next shade over.
Text
While often times a single color for text is enough, a lesser shade for de-emphasized text is welcome.
Primary
This IS your color theme, it’s the brand color. You’d want the main shade and a secondary
Auxiliary colors
These are great for semantics. For example, error messages, warnings, success, and tips/hints.
Colors are shades
Think of your palette in shades, you need 4-6 colors but a few shades of each.
For example:
Shades are powered by the HSLColor format because it allows us to control the color better than Hex or RGB can. HSL stands for Hue, Saturation, and Lightness.
- Hue: is degree on the color wheel, 0 to 360. //The actual color
- Saturation: is intensity of the color.
- Lightness: is how bright the color. This is how we make the shades.
Tip
Setting Saturation to 0 means no matter the Hue, it’ll always be a neutral grey. The shade of grey is manipulated using Lightness.
Quick five shade method
Select a color then change it to 5 different shades using the lightness value. Aim for 10, 30, 50, 70, and 90.
Background and Text
Must consider Dark and Light mode!
Background
Start with Hue and Saturation at 0% to achieve a neutral palette. //Some have suggested never using Sat at 0% but to add 2-3% for a more natural tone. Derive three shades for BG using the following Lightness values:
- 0% : dark black background base color
- 5%: cards and surface elements.
- 10%: important and raised elements. // Good for highlighting because lighter elements appear closer to the user.
Text
Same 00 for Hue and Saturation, but using the 70% and 95% Lightness shades for text. The 70% is for less important text but is still readable. // Don't use 100% lightness for text, it's too much.
Light mode
Super simple to do. Take the current palette used for Dark mode and subtract the Lightness values from 100% and that’s your Light mode base. Adjust if needed, use your intuition and taste because no fool-proof method exists and it’s always needed.
In Light mode, assume the light comes from the top, so raised elements should be lighter than surface elements but upon subtraction it’s often the opposite so swap them. Another handy trick is to name the background colors aptly.
Sajid uses bg-dark
, bg
and bg-light
. // I might just number them
CSS and Themes
Set your default theme for the :root{}
and the other one can be in a selector such as body.light{}
.
A single line of JavaScript is all that’s needed to toggle the theme.
you can also use media queries to check the user’s system preferences and set the theme based on that.
For example:
/* Theme preference colors */
@media (prefers-color-scheme: light) {
:root{
/*Light mode colors*/
}
}
@media (prefers-color-scheme: dark) {
:root {
/*Dark mode colors*/
}
}
Another method:
:root[data-theme="light"]{
/*Light mode colors*/
}
}
Adding some Life
There are four ways to make our flat and bland neutral color theme look more lively
- Borders
- Highlights
- Gradients
- Shadows
Borders
Should be clearly visible but not distracting. It shouldn’t draw attention nor be noticed, it’s there to separate and support.
Simple gradients
Created using our background color shades Example:
linear-gradient(0deg, var(--bg), var(--bg-light));
If it’s too much, only show the gradient on hover and give it a top shine instead. Shine example:
linear-gradient(0deg, var(--bg) 95%, var(--bg-light));
This well complimented by a lighter top border. // gives a sense of spotlight
Shadows
Are a terrific way to achieve what borders do for dark mode, since there’s light there should be a shadow around elements.
Shadows need Transparency, which means an alpha
value is needed and added to the HSLColor . Introducing the CSS HSLA function.
The Alpha value has a range of 0 to 1.
Example:
box-shadow: 0 4px 8px hsla(0, 0%, 0%, 0.7);
Combined Shadows
Instead of a single shadow, combine a darker shorter shadow with a lighter and longer shadow. This gives a more natural appearance to your shadows and tingles the human brain in the right way. Example:
.combined{
box-shadow: 0px 4px 4px hsla(0, 0%, 3%, 0.8), 0px 12px 12px hsla(0, 0%, 1%, 0.4);}
Introducing OKLCH
I’ve never seen OKLCH format before this. But apparently it’s fairly new as shown by these MDN docs dated June 23 2025
- L: Lightness
- C: Chroma which is kinda like Saturation…? Value range is 0-0.4
- H: Hue
Info
LCH is another color format. If HSL evolved to LCH, then LCH evolved to OKLCH