Achieving a dark or any color mode can be different project by project. Spruce CSS gives you the structure to handle themes, but it’s on you to manage end detect them.
Our method usually adds a data-theme-mode
attribute on the HTML element and does the styling based on its value. We detect the prefers-color-scheme
and/or the user settings, then add the dark value if needed.
<html lang="en" data-theme-mode="dark">
Setting up any theme mode is simple but can be tricky and complicated because of the many values (from the $colors
map). For redeclaring dark mode, we have a predefined empty $dark-colors
map which you can use when importing Spruce (but you can use any object you like).
First, declare the new colors, and keep in mind you have to use the same key names because we will overwrite them.
The following values are the ones that we use for this site’s dark mode.
@use 'sass:color';
$color-black: hsl(206deg 100% 7%);
$color-danger: hsl(0deg 71% 51%);
$color-gray: hsl(0deg 0% 97%);
$color-gray-dark: hsl(0deg 0% 100% / 8%);
$color-primary: hsl(261deg 54% 70%);
$color-secondary: hsl(227deg 92% 55%);
$color-success: hsl(150deg 100% 33%);
$color-white: hsl(0deg 0% 95%);
$colors: (
'base': (
'background': $color-black,
'blockquote-border': $color-primary,
'border': $color-gray-dark,
'code-background': hsl(207deg 64% 18%),
'code-foreground': $color-white,
'heading': $color-white,
'link': $color-primary,
'link-hover': color.scale($color-primary, $lightness: 20%),
'mark-background': hsl(50deg 100% 80%),
'mark-foreground': $color-black,
'marker': $color-primary,
'primary': $color-primary,
'secondary': $color-secondary,
'text': $color-gray,
),
'btn': (
'primary-background': hsl(261deg 52% 59%),
'primary-background-hover': hsl(261deg 52% 65%),
'primary-foreground': $color-white,
'primary-shadow': color.adjust($color-primary, $lightness: -25%),
'secondary-background': $color-secondary,
'secondary-background-hover': color.adjust($color-secondary, $lightness: 5%),
'secondary-foreground': $color-white,
'secondary-shadow': color.adjust($color-secondary, $lightness: -20%),
),
'form': (
'background': color.scale($color-black, $lightness: 5%),
'background-disabled': $color-black,
'border': $color-gray-dark,
'border-disabled': $color-gray-dark,
'border-focus': $color-primary,
'check-background': $color-primary,
'check-focus-ring': $color-primary,
'check-foreground': $color-black,
'group-label-background': color.scale($color-black, $lightness: 2.5%),
'group-label-foreground': $color-gray,
'invalid': $color-danger,
'invalid-focus-ring': color.adjust($color-danger, $alpha: -0.75),
'label': $color-white,
'legend': $color-white,
'placeholder': hsl(0deg 0% 60%),
'range-thumb-background': $color-primary,
'range-thumb-focus-ring': $color-primary,
'range-track-background': $color-gray-dark,
'ring-focus': color.adjust($color-primary, $alpha: -0.75),
'select-foreground': hsl(0deg 0% 100%),
'text': $color-gray,
'valid': $color-success,
'valid-focus-ring': color.adjust($color-success, $alpha: -0.75),
),
'selection': (
'background': $color-primary,
'foreground': $color-white,
),
'scrollbar': (
'thumb-background': hsl(0deg 0% 100% / 15%),
'thumb-background-hover': hsl(0deg 0% 100% / 25%),
'track-background': hsl(0deg 0% 100% / 5%),
),
'table': (
'border': $color-gray-dark,
'caption': $color-gray,
'heading': $color-white,
'hover': hsl(0deg 0% 100% / 5%),
'text': $color-gray,
'stripe': hsl(0deg 0% 100% / 2.5%),
),
);
Use the generate-color-variables
to generate the color variables under a specified selector.
@use 'sprucecss/scss/spruce' as *;
@include generate-color-variables(
$dark-colors,
':root[data-theme-mode="dark"]'
);
Usually, setting up a theme is not just mean overwriting the color variables. We want to do more.
For example, we want to set the color-scheme
to dark
to discolor the scrollbars. Also, in the case of Spruce CSS, we may wish to change the select image too.
[data-theme-mode="dark"] {
color-scheme: dark;
select.form-control:not([multiple]):not([size]) {
@include field-icon(
config('select', $form-icon, false),
color('select-foreground', 'form', true, $dark-colors)
);
}
}