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
green
amber
red
gray
Also available:
- A built-in dark theme.
- 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.
Example border, text and background utilities:
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:
<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">
☆ 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 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:
- Useful blog posts from The Accessibility (A11Y) Project:
- Web Content Accessibility Guidelines (WCAG) 2
- Contrast and Color Accessibility (WEB AIM)
- The Coolors contrast checker
- Web Accessibility: Understanding Colors and Luminance (Mozilla Developer Network Docs)
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
Other color utilities included in Baselayer cover black, white, and transparent.
Black and white
*-black
— named color black*-white
— named color 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.
<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
.