AniUI Academy

Colors and Backgrounds

The color formats CSS understands — keyword, hex, rgb() and hsl() — background-image with linear-gradient, controlling size/position/repeat, and the currentColor keyword.

8 min read

You've been using a handful of color keywords already without thinking about it much — navy, red, white. CSS actually gives you several distinct ways to describe a color, and picking the right one changes how easy your stylesheet is to reason about and adjust later.

Four ways to write a color

.keyword   { color: rebeccapurple; }
.hex       { color: #3b82f6; }
.rgb       { color: rgb(59, 130, 246); }
.rgb-alpha { color: rgba(59, 130, 246, 0.5); }
.hsl       { color: hsl(217, 91%, 60%); }
.hsl-alpha { color: hsla(217, 91%, 60%, 0.5); }
  • Keyword — a named color like red, navy, rebeccapurple. Readable, but there are only a fixed set of names and no way to fine-tune one.
  • Hex#rrggbb, three pairs of hexadecimal digits for red, green and blue. Extremely common, especially when copying a color from a design tool, but the digits themselves don't tell you much at a glance — #3b82f6 gives you no intuition for what it looks like until you've seen it rendered.
  • rgb() — the same red/green/blue values written as plain numbers 0–255 (or percentages). rgba() adds a fourth value, alpha, from 0 (fully transparent) to 1 (fully opaque).
  • hsl() — hue (0–360, a position on the color wheel), saturation (0–100%, how vivid), lightness (0–100%, how close to black or white). hsla() adds the same alpha channel.

Modern CSS also lets you write rgb(59 130 246 / 0.5) and hsl(217 91% 60% / 0.5) — space-separated with a slash before alpha — but the comma syntax above works everywhere and is still extremely common; either is fine to reach for.

Why HSL is often easier to reason about

Hex and RGB describe a color as a mix of red, green and blue light — accurate, but not how humans naturally think about color. "Make this a bit darker" or "give me five shades of the same blue" is genuinely hard to do by adjusting hex digits, because darkening a color changes all three RGB components in a way that isn't obvious from the numbers.

HSL separates which color (hue) from how intense (saturation) and how light or dark (lightness). That means you can hold hue and saturation constant and vary only lightness to get a consistent family of shades of the same color:

:root {
  --brand-hue: 217;
  --brand-sat: 91%;
}
 
.brand-light { color: hsl(var(--brand-hue) var(--brand-sat) 85%); }
.brand-base  { color: hsl(var(--brand-hue) var(--brand-sat) 60%); }
.brand-dark  { color: hsl(var(--brand-hue) var(--brand-sat) 35%); }

Same hue, same saturation, three lightness values — three clearly related shades, and the relationship between them is visible directly in the numbers rather than hidden inside three separately-tweaked hex codes. This is a real, practical reason designers and developers often reach for HSL when building a palette by hand, even though hex remains extremely common for one-off colors picked from a design file.

background-color

The simplest background: a flat fill behind an element's content.

.card {
  background-color: #f8fafc;
}

Any of the color formats above work here.

background-image with linear-gradient()

background-image isn't limited to photos — CSS can generate a gradient directly, no image file needed:

.banner {
  background-image: linear-gradient(90deg, #3b82f6, #8b5cf6);
}

The first argument is the direction90deg points left to right (CSS gradient angles start pointing up at 0deg and rotate clockwise, so 90deg is "to the right"). You can also use keywords instead of degrees:

.banner-alt {
  background-image: linear-gradient(to right, #3b82f6, #8b5cf6);
}

After the direction come color stops — the colors the gradient passes through, evenly spaced by default. You can add more than two, and you can pin any stop to a specific position with a percentage:

.sunset {
  background-image: linear-gradient(
    to bottom,
    #fbbf24 0%,
    #f97316 50%,
    #7c3aed 100%
  );
}

Controlling size, position and repeat

Three properties shape how a background image (gradient or photo) fills its element:

.hero {
  background-image: url("photo.jpg");
  background-size: cover;      /* fill the box completely, cropping if needed */
  background-position: center; /* keep the middle of the image visible */
  background-repeat: no-repeat; /* don't tile it */
}
  • background-sizecover scales the image to fill the element entirely (cropping overflow), contain scales it to fit entirely inside without cropping, and you can also give explicit lengths or percentages.
  • background-position — where the image is anchored within the element, using keywords (center, top right) or lengths.
  • background-repeat — by default, a background image smaller than its element tiles to fill the remaining space. no-repeat stops that; repeat-x and repeat-y tile in only one direction, which is useful for a background pattern or a thin repeating texture strip.

currentColor: matching whatever text color already applies

currentColor is a keyword, usable anywhere a color value is expected, that always resolves to the element's own computed color value. It's genuinely useful anywhere you want something to match the surrounding text color without duplicating that color value a second time:

.link-with-icon {
  color: #1d4ed8;
  border-bottom: 1px solid currentColor; /* always matches the text color above */
}
 
.link-with-icon svg {
  fill: currentColor; /* the icon tints to match the link's text color too */
}

Change .link-with-icon's color later — a rebrand, a dark theme, a hover state — and the border and the SVG icon fill update automatically, because both are defined relative to whatever color currently is rather than a second hardcoded value that would otherwise drift out of sync.

Try it yourself

Try it yourself
Loading playground...

What to remember

  • CSS colors: keyword, hex, rgb()/rgba(), hsl()/hsla() — all interchangeable wherever a color is expected.
  • HSL separates hue, saturation and lightness, so holding hue/saturation fixed and varying lightness gives you a consistent set of shades — something hex and RGB don't make easy.
  • linear-gradient(direction, stop, stop, ...) generates a gradient with no image file; stops can be pinned to positions with percentages.
  • background-size: cover/contain, background-position, and background-repeat: no-repeat control how a background fills its box.
  • currentColor always resolves to the element's own text color — use it so a border, fill, or shadow stays in sync with color automatically instead of duplicating the value.