Skip to page content

Colors

color-mix(in OKLCH ... ) has been Baseline:widely available since March 2023 — all “evergreen” browsers (Chrome, Edge, Firefox, Safari) have capability to use it (see Can I use). Baselayer uses this function to set up a range of lightness levels for its built-in colors.

Rationale for Baselayer’s color system

I wanted to develop a color system based on interpolating CSS variables for generating a series lightness levels for each color, so that the stylesheet doesn’t need to be loaded with lighness classes for every color — most of which you’d never use.

After experimenting with variables in lightness channels within color codes, I discovered the new (mid-2023) color-mix() function. Using color-mix() is better suited to what I was trying to do. With it we can build a series of lightness levels by mixing in white (for tints) or black (for shades).

For usefulness in Baselayer CSS, starting color swatches need to have a mid-range lightness level, but they can be specified using any system (currently, Baselayer default colors are set using Hex # codes). And the color-mix function now outputs colors in OKLCH using color-mix(in OKLCH ...) because I this gives perceptually uniform lightness levels.

The color utility CSS class names remain the same as before (explained below). Example using background bg-* utility classes:

blue
100
200
300
400
500
600
700
800
900
green
100
200
300
400
500
600
700
800
900
amber
100
200
300
400
500
600
700
800
900
red
100
200
300
400
500
600
700
800
900
gray
100
200
300
400
500
600
700
800
900

Also available:

  1. A built-in dark theme.
  2. Black, white, and transparent — see other Baselayer color utilities.

Color and shade utility classes

All colors and lightness levels are declared in variables.css.

Color utility classes (declared in @layer color in colors.css) are prefixed acording to where the color will be applied — border b-* text t-* or background bg-*. I have named the colors according to their common names (blue, green, amber, red, gray). You can modify the root variables of these colors, and you can add your own colors.

Border Color Text Color Background Color
Default state Hover state Default state Hover state Default state Hover state
Base color class b-* hover:b-* t-* hover:t-* bg-* hover:bg-*
Lightness modifier b-100
...
b-900
hover:b-100
...
hover:b-900
t-100
...
t-900
hover:t-100
...
hover:t-900
bg-100
...
bg-900
hover:bg-100
...
hover:bg-900

Example border, text and background utilities:

b-green
t-green t-600 t-dark-invert
bg-green bg-200

See also inverting lightness levels for the dark theme

<div class="b-heavy b-green"></div>
<div class="t-green t-600 t-dark-invert"></div>
<div class="t-black bg-green bg-300"></div>

Example usage:

☆ Note (information) panel.
<div aria-label="Note" class="popout mt-3 mb-4 bl-heavy b-blue b-400 b-dark-invert p-3 t-black t-dark-invert bg-blue bg-200 bg-dark-invert">
  &star; Note (information) panel.
</div>

The lighness modifiers *-100 through *-900, if used alone, do not provide color. But if you use them to supplement one of the base colors above, then that color class will provide the color, and the modifier will set its lightness level.

Colors and accessibility

In any color model, color combinations must be chosen with care so that there is sufficient contrast between text and background colors for purposes of assessibility.

In your text and background color combinations, be careful to ensure that the text is readable — there needs to be an adequate contrast. Most organizations should to aim for WCAG level AA for accessibility requirements.

For WCAG level AA conformance, most user interface colors need to be darker than the mid-level (i.e. use *-600 up) if the text color is white, or lighter than the mid-level (i.e. use *-400 down) if the text color is black.

However, any colors near yellow such as Baselayer amber, as well as orange and yellow-green (not included), are especially difficult for accessibility. You may do better using a lighter background amber and pairing it with black text (or vise versa).

When colorizing buttons, remember to set their hover: hover state shades too.

<!-- Default button -->
<button type="button" name="button">Button</button>

<!-- Blue button -->
<button class="bg-blue bg-600 hover:bg-700" type="button" name="button">Button</button>

<!-- Amber button -->
<button class="t-black hover:t-black bg-amber bg-500 hover:bg-600" type="button" name="button">Button</button>

<!-- Green outline (a.k.a. ghost) button -->
<button class="b-thin b-green bg-transparent t-green t-600 hover:b-700 hover:t-white hover:bg-green hover:bg-700" type="button" name="button">Button</button>

Background reading on colors and accessibility:

Adding more colors

You can, of course, add any colors you want, and in any format you want.

However, if you want to use Baselayer’s lightness modifier classes -100 thorugh -900 on your colors, then you need to start from a mid-lightness color so that the -100 and the -900 generated by the color-mix() formulas are distinguishable (not to chose to white or too close to black).

Also, you will need to put your color(s) in CSS layer @layer colors {} so that they take precence over the Baselayer lightness modifiers and other color utilities.

You can add your own project colors in any format, but the Baselayer color-mix() formulas will output shade in OKLCH format.

Examples:

:root {
  --purple: #9400d3;
  --teal: #0080A2;
}

@layer colors {
  .bg-purple,
  .hover\:bg-purple:hover {
    --bgc: var(--purple);
    background: var(--bgc);
  }
  .bg-teal,
  .hover\:bg-teal:hover {
    --bgc: var(--teal);
    background: var(--bgc);
  }
}

Dark theme

Baselayer has a simple dark theme built in. Since v.3.4.0, the user’s operating system preference for light or dark mode is automatically detected on the HTML tag:

html {
  color-scheme: light dark;
}

For the dark theme, HTML elements are generally flipped from light to dark, or dark to light, as required:

  • Body background is near black
  • Text is near white
  • Table borders, horizontal rules, form inputs are dark gray
  • Text links are a lighter blue
  • Default buttons are a lighter gray

All the theme color variables in Baselayer (since v.3.4.0) involve a light-dark() CSS function. For example:

:root {
  /*
  Body tag background color
  */
  --bgc-body: light-dark(
    white,
    color-mix(in OKLCH, var(--gray), var(--l1000))
  );

  /*
  Base text color (also set on the body tag)
  */
  --tc-base: light-dark(
    color-mix(in OKLCH, var(--gray), var(--l900)),
    color-mix(in OKLCH, var(--gray), var(--l100))
  );
}

Baselayer does not use @media (prefers-color-scheme: dark) {} anywhere.

The color shade utilities can optionally be inverted by adding the *-dark-invert modifier classes.

Light and dark theme classes

If you wish to give your visitors the option to switch between light and dark modes, you can include a JavaScript that swaps between CSS classes theme-light and theme-dark on the HTML tag. Baselayer has these two tags built in, so that you can implement the style selection:

html {
  color-scheme: light dark;
  &.theme-light {
    color-scheme: light;
  }
  &.theme-dark {
    color-scheme: dark;
  }
}

Example implementation: the Baselayer documentation has demo JavaScript switches for light, dark, and auto modes. The auto mode removes theme-light and theme-dark from the <html> tag, so that you simply get the Baselayer default, that is the user’s operating system theme preference setting.

Inverting lightness levels for the dark theme

There will be many situations in your design where you want your utility color shades flipped for the dark theme, same way as the background color is flipped from white to near black, and son on. For handling this, Baselayer has three optional *-dark-invert modifier classes that flip the lightness modifier utility values.

/* Border lightness inverter */
.b-dark-invert

/* Text lightness inverter */
.t-dark-invert

/* Background lightness inverter */
.bg-dark-invert

Example using bg-blue:

<div class="bg-blue bg-100"></div>

<div class="bg-blue bg-100 bg-dark-invert"></div>
Shade bg-blue bg-blue bg-dark-invert
bg-100    
bg-200    
bg-300    
bg-400    
bg-500    
bg-600    
bg-700    
bg-800    
bg-900    

(The middle t-500, b-500, and bg-500 do not invert.)

Dark theme HTML body background color

For dark teme, Baselayer’s <body> background color has been set by color-mix(in OKLCH, var(--gray), var(--l1000). This darkest shade level --l1000 (near black) is only used on the <body> tag, and it has been set so that all Baselayer bg-900 shades will still be seen by many people.

What if you don’t want a dark theme?

Then you can simply override or replace the HTML tag as follows:

html {
  color-scheme: light;
}

(And you won’t need to use any *-dark-invert classes.)

Other Baselayer color utilities

The color utilities for black, white, and transparent can’t be used on the same element with the colors and shades above (i.e. as either default or hover states). These other utilities are declared after the colors and shades, and so they will override them.

Other color utilities included in Baselayer cover black, white, and transparent.

Black and white

  • *-black — named color black
  • *-white — named color white
t-white bg-black
t-black bg-white

Inverting black and white for the dark theme

New in Baselayer v.3.4.0: The *-dark-invert classes also work on the black and white utilities, enabling a reversi effect when the user prefers the dark theme.

t-white t-dark-invert bg-black bg-dark-invert
t-black t-dark-invert bg-white bg-dark-invert
<div class="t-white bg-black">...</div>

<div class="t-black bg-white">...</div>

<div class="t-white t-dark-invert bg-black bg-dark-invert">...</div>

<div class="t-black t-dark-invert bg-white bg-dark-invert">...</div>

Transparent background

E.g. for outline buttons.

  • Transparent:
    • bg-transparent

There are no hover states of bg-transparent.