No site ships without color, but writing one correctly in CSS has long been a source of confusion: the language accepts several different syntaxes for the exact same shade, and they are not interchangeable depending on what you plan to do with them.
This entry walks through the available formats, the properties a color can be applied to, and the most common trap: mixing up a fully opaque color with a transparent one.
Definition
In CSS, color has no property of its own: it is a value passed to any property that accepts one, such as color for text, background-color for a background, or border-color for an outline. The language offers several syntaxes for writing the same color, and none of them is objectively better: they simply answer different needs.
The available formats
A keyword (red, tomato, rebeccapurple) is the most readable, but it only covers the 148 names fixed by the specification. The hexadecimal format (#ff6600) is the most compact, and it is what most design tools hand you when you copy a swatch. The functions rgb() and hsl() describe a color through its components rather than an opaque code, which makes them easier to tweak by hand. A more recent function, oklch(), fixes a flaw shared by the two: it represents lightness changes in a way that matches human perception more evenly, so two shades that look close on paper no longer end up looking wildly different once rendered.
.primary-button {
color: white;
background-color: #ff6600;
}
.primary-button:hover {
background-color: rgb(230 90 0);
}
.card {
background-color: hsl(24 100% 50%);
border: 1px solid oklch(70% 0.15 40);
}Where a color can be applied
Color is not limited to text or backgrounds. It shows up in an element's outline, in a shadow, in a gradient, or in the focus ring shown when navigating with a keyboard. Any property whose documentation mentions a <color> value accepts any of the formats above, and you can freely mix formats across different properties in the same stylesheet.
| Format | Example | When to use it |
|---|---|---|
| Keyword | tomato | Quick prototyping, neutral colors |
| Hex | #ff6600 | Color copied from a mockup |
rgb() | rgb(255 102 0) | Readable components, transparency possible |
hsl() | hsl(24 100% 50%) | Tweaking a shade by hand (lighter, darker) |
oklch() | oklch(70% 0.2 40) | A perceptually consistent palette |
Transparency is its own case
Keywords and the six-digit hex format allow no transparency at all: the color is fully opaque or it is not a color you can use. A partially transparent color needs a fourth channel, called the alpha channel. That is exactly the role of rgba() and hsla(), which adds that information without touching the rest of the layout.
#ff660080) to bake in transparency, but it stays less readable than a four-value rgb(): save it for colors already generated automatically by a tool.Best practices
Typing out the same color literally in fifteen different places is the first source of visual drift: a button that ends up slightly more orange than another, without anyone deciding it should be. The common practice is to centralize every color in a CSS custom property, then never write a literal value inside components themselves. A rebrand becomes a single edit instead of a search-and-replace hunt across the whole project. Our HTML and CSS course sets up this exact color variable system from the very first projects, building the habit before a site grows too large to do without it.
Frequently asked questions
#fff work?Because each character is automatically doubled: #fff is exactly equivalent to #ffffff, and #039 is equivalent to #003399. This shorthand only works when both digits of each component are identical, which is not always true for an arbitrary color.
hsl() be preferred over rgb()?It depends where the color comes from. If it comes from a mockup that gives red, green, blue values, rgb() avoids a conversion step. If you need to tweak a shade by hand, for example darkening a color on hover, hsl() is more intuitive: you only lower the third number, lightness, instead of recalculating three components at once.
Yes, without repeating it, thanks to a special keyword called currentColor. It automatically picks up the computed value of the element's color property, which avoids keeping two values in sync by hand whenever one of them changes.