CSS Colors and Units: Hex, RGB, Rem, Em, and Viewport Units

Published Updated

CSS color formats are different recipes for mixing the same paint, while each CSS unit tells the browser which reference to measure from. Start with the syntax below, then choose a format or unit whose reference is clear to the next person reading the rule. For the broader styling basics, start with the guide to CSS. This guide is part of our CSS typography and color guide series.

.notice {
  color: hsl(222 47% 11%);
  background: rgb(219 234 254 / 80%);
  border: 1px solid #93c5fd;
  padding: 1rem;
  width: 80%;
}

The notice uses HSL for opaque text, RGB with an alpha channel for a translucent background, hex for a compact border color, rem for root-relative spacing, and a percentage width tied to its parent.

CSS Color and Unit Syntax

A color value can be a keyword, a hexadecimal string, or a function. Modern rgb() and hsl() syntax separates channels with spaces. If the color needs transparency, a slash separates the three color channels from the optional alpha value.

Lengths combine a number with a unit, such as 16px, 1rem, or 40vw. A percentage is resolved against a property-specific reference. For example, width: 50% uses the containing block's width, while font-size: 120% uses the parent's font size.

Color Keywords

Named colors make early examples easy to read because their meaning is visible in the declaration. CSS defines keywords such as tomato, rebeccapurple, and transparent, but a product palette usually needs more precise values than names provide.

.status {
  color: navy;
  background: lightyellow;
  border-color: tomato;
}

Use keywords for learning, quick prototypes, and familiar values such as transparent. Use a numeric format when a design requires an exact shade.

Hex Colors

Hex writes the paint recipe as compact red, green, and blue hexadecimal pairs after #. The six-digit value #2563eb copies cleanly from design tools. Three-digit shorthand works only when every pair repeats, so #fff expands to #ffffff.

.button {
  color: #ffffff;
  background: #2563eb;
  border-color: #1d4ed8;
}

An eight-digit hex value adds an alpha pair at the end. The eight-digit example #2563eb80 uses approximately 50% opacity. The compact form is valid, but the alpha pair is less obvious than slash-alpha syntax during review.

RGB Colors and Slash Alpha

rgb() spells out the same paint recipe through red, green, and blue channels written as numbers from 0 to 255 or percentages from 0% to 100%. Modern syntax uses spaces between channels, then an optional slash followed by a number or percentage for alpha.

.overlay {
  background: rgb(15 23 42 / 70%);
}

.overlay-light {
  background: rgb(15 23 42 / 0.25);
}

The first background is 70% opaque, and the second is 25% opaque. This syntax is a good fit when a color comes from RGB channel values or when transparency needs to remain immediately visible.

HSL Colors and Slash Alpha

The hsl() paint recipe uses hue, saturation, and lightness. Hue moves around a color wheel, saturation controls color intensity, and lightness moves from black through the chosen color to white. Keeping hue and saturation steady makes related light and dark variants easier to edit by hand.

.tag {
  background: hsl(217 91% 60%);
}

.tag-soft {
  background: hsl(217 91% 85% / 80%);
}

The slash before 80% performs the same alpha job as it does in rgb(). Both functions use the modern space-separated form, so the color channels stay visually separate from opacity.

Which CSS Color Format Should You Use?

Use hex for compact color codes, rgb() for red/green/blue channels, and hsl() when adjusting hue, saturation, and lightness is easier. Each can describe the same sRGB color; consistency within your project matters more than choosing one universally best format.

FormatBest fit
KeywordReadable examples, prototypes, and familiar special values.
HexCompact opaque colors copied from a design specification.
rgb()RGB channel values and clearly written transparency.
hsl()Related shades adjusted through hue, saturation, or lightness.

How Do CSS Length Units Work?

CSS length units tell the browser what a measurement is relative to. Pixels are reference units, rem follows the root font size, em uses the parent’s font size when setting font-size and the element’s own font size for most other lengths, and viewport units follow the browser viewport. Percentages use a reference determined by the property.

  • px is an absolute CSS length suited to thin borders and small fixed details.
  • rem uses the root element's font size, which makes it a steady choice for type and spacing.
  • em on font-size uses the parent's font size; on most other properties, it uses the element's own font size.
  • % uses a reference defined by the property, often the parent or containing block.
  • vw equals 1% of the viewport width and suits dimensions that intentionally track the screen.

Worked Card Example

.card {
  width: 80%;
  max-width: 40rem;
  padding: 1.5rem;
  border: 1px solid #93c5fd;
  color: hsl(222 47% 11%);
  background: rgb(219 234 254 / 80%);
}

.card__title {
  margin-bottom: 0.5em;
  font-size: 1.5rem;
}

With a 16px root size, the card's 1.5rem padding computes to 24px and the title's 1.5rem size also computes to 24px. The title's 0.5em bottom margin then computes from that local 24px font size, producing 12px. The percentage width follows the parent, while max-width stops the card from growing indefinitely.

Common Pitfalls & Debugging

em Values Compound Through Nesting

Nested text gets larger at every level. Each element uses an em font size calculated from its parent's already enlarged value. Use rem when every level should share one root-based size.

.menu {
  font-size: 1.2em;
}

/* Fix: rem replaces the compounding em. */
.menu .menu {
  font-size: 1rem;
}

Hex Alpha Is Easy to Misread

An eight-digit hex color has unexpected opacity. Its final pair encodes alpha in hexadecimal, so 80 means about 50%, not 80%. Use slash-alpha RGB or HSL when reviewers need to read transparency directly.

Mixed Units Hide the Scaling Rule

Related spacing changes at different rates. The component mixes root-relative, local-font, parent, and viewport references without a reason. Choose units by job, document exceptions, and keep related values on the same scale.

Choose Units for What Should Resize

Choose a color recipe that makes its channels readable, then choose each unit from the reference the property should follow. Consistent choices make later edits easier to predict.

Frequently Asked Questions

Is a CSS pixel one device pixel?

A CSS pixel is a reference unit rather than a guaranteed physical screen dot. High-density screens can use several device pixels to render one CSS pixel, and browser zoom can scale dimensions written in px.

Can a CSS calc() expression mix units?

CSS calc() can combine compatible units, such as calc(100% - 2rem) for a width. The browser resolves each part against its appropriate reference. The result must still be a valid value for the property using it.

What does one rem equal in CSS?

One rem equals the root element’s computed font size. That commonly starts at 16px, but browser preferences or your CSS can change it. Avoid fixing the root size in pixels if you want rem-based text to follow the reader’s default preference.

Should CSS layout widths use percentages or vw?

Use percentage widths when an element should scale with its containing block. Use vw when it should scale with the viewport. Add a suitable maximum width so text does not stretch into long, difficult lines.

Can CSS custom properties store color values?

CSS custom properties can store reusable colors. Declare a name such as --brand-color on :root or a component, then use var(--brand-color) in color properties. Changing that value updates the elements that use it, unless a local declaration overrides it.

Sources

  1. [1]
    CSS color values
    (developer.mozilla.org)
  2. [2]
    <length> CSS data type
    (developer.mozilla.org)
  3. [3]
    CSS values and units
    (developer.mozilla.org)