Variables and Modes
Learn how to use theme variables and modes in your CSS.
Overview
This document explains how to define and use variables and modes in the Master CSS framework. Variables allow for reusable values throughout your styles, while modes enable conditional styling for different contexts like light/dark themes.
For a classic example, use the primary
token in your markup:
<div class="bg:#000000@light">…</div> <div class="bg:#ffffff@dark">…</div> <div class="bg:primary">…</div>
Design tokens are a fundamental part of design systems and are crucial for maintaining design consistency and efficiency in projects, especially in larger organizations or projects with complex design requirements. They help bridge the gap between design and development, promoting collaboration and ensuring a cohesive user experience.
Understanding variables
Variables in Master CSS provide a way to define reusable values that can be referenced throughout your styling. They help maintain consistency and make theme changes simpler.
Defining variables
Variables are defined in the variables
section of your configuration file. The basic syntax follows a hierarchical structure:
export default { variables: { full: '100%', spacing: { md: 20, }, color: { black: '#000', /* <─┐ */ primary: '$color-black', /* ──┘ linked to black */ } }}
- Variable
black
is parsed as a color-type variable. - Variable
primary
is linked to$color-black
and parsed as a color-type variable. - Variable
full
is parsed as a string-type variable. - Variable
md
is parsed as a number-type variable.
Spacing variables should be defined in spacing
section.
Using variables in classes
Once defined, you can use these variables in your markup. The syntax for using variables is straightforward:
<div class="bg:black">…</div><div class="bg:primary">…</div><div class="w:full">…</div><div class="m:md">…</div>
Generated CSS
@layer base, theme, preset, components, general;@layer general { .m\:md { margin: 1.25rem } .bg\:black { background-color: rgb(0 0 0) } .bg\:primary { background-color: rgb(0 0 0) } .w\:full { width: 100% }}
Contextual resolution of variables
Master CSS resolves variable names like primary
based on their usage context. When used with color-related properties — such as background-color
or its shorthand bg
— the system maps primary
accordingly:
<div class="background-color:primary">…</div><div class="bg:primary">…</div>
This contextual alias resolution avoids conflicts with similarly named variables and ensures consistent, predictable behavior. For example, variables.primary
always maps to a color property when used in a color context, never to unrelated properties. This design promotes concise, semantic markup without sacrificing clarity.
Namespace-aware variable mapping
Variables can be defined within the namespace of a specific CSS property and applied using shorthand syntax. For example, you can define a custom font-family
variable in your configuration:
export default { variables: { 'font-family': { 'open-sans': 'Open Sans' } }}
Once defined, you can reference the variable in your markup using the shorthand property:
<div class="font-family:open-sans">…</div><div class="font:open-sans">…</div>
This ensures that open-sans
is only interpreted as a font-family
value, promoting both clarity and brevity in your code.
Variable inlining mechanism
For non-mode variables, optimization is achieved by directly inlining values #000
and removing intermediate references variables.primary
.
.bg\:primary { background-color: #000;}
You can also use native CSS variable declarations explicitly, but it will not generate --primary: #000
rules and you will have to define them manually as usual.
<div class="fg:var(--color-primary)">…</div>
It will be compiled to:
.fg\:var\(--color-primary\) { color: var(--color-primary);}
Modes for variables
Modes in Master CSS allow you to define different variable values based on the context, such as light or dark themes. This enables you to create responsive designs that adapt to user preferences or system settings.
Modes can be applied to individual classes using the @<mode>
syntax:
<div class="bg:black@dark">…</div><div class="bg:white@light">…</div>
Generated CSS
@layer base, theme, preset, components, general;@layer general { @media (prefers-color-scheme:dark) { .bg\:black\@dark { background-color: oklch(0% 0 none) } } @media (prefers-color-scheme:light) { .bg\:white\@light { background-color: oklch(100% 0 none) } }}
However, when attempting to implement a complete design system, marking the mode in the template not only clutters the markup but also makes your design structure harder to standardize and maintain.
Defining variables with modes
Variable modes are defined in the modes
section of your configuration file. For example, add color variables in different modes.
export default { variables: { color: { primary: '#ff0000' } }, modes: { light: { color: { primary: '#000000' } }, dark: { color: { primary: '#ffffff' } } }}
- The dark mode defines a
primary
color of#000000
. - The light mode defines a
primary
color of#ffffff
. - The default defines a
primary
color of#ff0000
.
Using mode variables in classes
You can use mode variables like primary
in your markup by applying the same variable name in different contexts without confusion.
<div class="bg:primary">…</div>
Generated CSS
@layer base, theme, preset, components, general;@layer theme { :root { --color-primary: rgb(255 0 0) } @media (prefers-color-scheme:light) { :root { --color-primary: rgb(0 0 0) } } @media (prefers-color-scheme:dark) { :root { --color-primary: rgb(255 255 255) } }}@layer general { .bg\:primary { background-color: var(--color-primary) }}
Since Master CSS recognizes that the primary
variable is mode-dependent, it compiles it into a standard CSS custom property and accesses it via the var(--primary)
syntax.
Mode triggers
Master CSS supports three mode triggers, allowing you to choose how modes are applied in your styles. The available triggers are:
media
Uses media queries to apply the mode based on user preferences.class
Applies the mode based on a class name.host
Applies the mode based on the shadow host element's class.
export default { modeTrigger: 'media' /* default */ }
For example, apply the background color #000
in dark mode:
<div class="bg:black@dark">
By default, drive theme styles through 'media'
queries:
@media (prefers-color-scheme: dark) { .bg\:#000000 { background-color: #000000 }}
Drive theme styles through 'class'
names:
.dark .bg\:#000000 { background-color: #000000}
Drive theme styles through shadow DOM's 'host'
:
:host(.dark) .bg\:#000000 { background-color: #000000}
Default mode
The default mode is applied when no specific mode is specified. You can set the default mode in your configuration file:
export default { defaultMode: 'light', /* default */ modeTrigger: 'class'}
With default 'light'
mode:
.light, :root { --color-primary: 0 0 0;}
No default mode false
:
.light { --color-primary: 0 0 0;}
The defaultMode
has no effect with 'media'
trigger, as CSS always applies either light or dark color preferences based on the user's system settings.
Implementing mode switching
You can use the prefers-color-scheme
media query to detect the user's system preference. However, CSS does not allow you to control the user's prefers-color-scheme
.
Using class-driven styles
To enable manual mode switching, use a class-based approach instead.
export default { modeTrigger: 'class' }
Then you can control the theme mode by adding the dark
class to the <html>
:
<html class="dark"> <body> <div class="bg:primary">…</div> </body></html>
Detect and store user preferences
To detect and store user preferences, use JavaScript to check the user's system preference and store it in localStorage
. This allows you to persist the user's choice across sessions.
const key = 'theme-preference';const defaultPreference = 'system';const preference = localStorage.getItem(key) || defaultPreference;const value = preference === 'system' ? matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light' : preference;document.documentElement.classList.add(value);if (['dark', 'light'].includes(value)) { document.documentElement.style.colorScheme = value;}
This code checks the user's preference and applies the appropriate class to the <html>
element. It also sets the color-scheme
property to ensure proper rendering of colors in the selected mode.