Creating Variables
A guide to using variables to implement design tokens.
Overview
In Master CSS, variables are used to manage tokens in the design system, such as colors, font families, breakpoints, etc., even based on different theme modes.
import { variables } from '@master/css' export default { variables: { 'font-family': { sans: 'Inter' }, screen: { desktop: 1280 }, spacing: { sm: 10 }, primary: '#000000' }}
Apply custom variables using ambiguous shorthand:
<div class="font:sans max-w:screen-desktop m:sm 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.
Fonts
By default, Master provides three font family variables, sans
, serif
, and mono
, to facilitate your use as fallbacks when adding custom fonts.
Add fonts
Customize your font tokens by defining variables. For example, add Inter
as the general font and Fira Code
as the code font.
import { variables } from '@master/css' export default { variables: { 'font-family': { sans: ['Inter', ...variables['font-family'].sans], mono: ['Fira Code', ...variables['font-family'].mono] } }}
Apply the defined font-family
variables. For example, presetting the global fonts in <body>
:
<body class="font:sans font:mono_:where(code,pre) font-feature:'salt'">…</body>
Don't forget to add the font faces.
Colors
Each color in the default color palette has a hue range from 5 to 95, which you can choose from as your brand's primary color.
5
#f0f1fe
10
#e9ecfe
20
#c8cdfe
30
#939eff
40
#7e81fe
50
#7068ff
60
#5b4cfd
70
#4e39ed
80
#4732d2
90
#3623a3
95
#26176c
For example, inherit from indigo:
import { variables } from '@master/css' /** @type {import('@master/css').Config} */export default { variables: { primary: variables.indigo }}
Apply them using the relevant syntax:
<div class="bg:primary-5 fg:primary-60">…</div>
Add a color
Add the primary color using #000
, rgb(0 0 0)
, or hsl(0 0% 0%)
.
export default { variables: { primary: '#000' }}
Apply it using color-related syntax and even change the opacity.
<div class="fg:primary bg:primary/.5">…</div>
Generated CSS
.bg\:primary\/\.5 { background-color: rgb(0 0 0/.5)} .fg\:primary { color: rgb(0 0 0)}
If a color is used only once in all markups, you can optionally not abstract it into a token.
<button class="bg:#ceb195">Milk Tea</button>
Variables only support rgb
and hsl
, in the future, they will be compatible with all native CSS functions, such as rgba
, hsla
, lab
, and others. #346
Add a color with opacity
Add color variables with opacity using #00000080
, rgb(0 0 0/.5)
, or hsl(0 0% 0%/.5)
.
export default { variables: { primary: 'rgb(0 0 0/0.5)' }}
Apply it using color-related syntax like fg:
.
<div class="fg:primary">…</div>
Generated CSS
.fg\:primary { color: rgb(0 0 0 / .5)}
Color variables with opacity cannot use /alpha
to change the opacity.
<div class="fg:primary/.5">…</div>
Add a color alias
Create an alias for a color to link its value to an existing color.
export default { variables: { secondary: '$(blue-60)' }}
Apply it using color-related syntax.
<div class="fg:secondary">…</div>
Generated CSS
.fg\:secondary { color: rgb(37 99 253)}
For example, say you have multiple color variables referencing the same color token. If that color needs updating, you would only need to update the source instead of manually updating every instance of the color.
Add a color alias with opacity
Create an alias for a color with opacity to link its value to an existing color.
export default { variables: { primary: '$(black)/.5', // <─┐ secondary: '$(primary)/.5' // ──┘ linked to primary }}
Apply it using color-related syntax like fg:
.
<div class="bg:primary fg:secondary">…</div>
Generated CSS
.bg\:primary { background-color: rgb(0 0 0 / .5)} .fg\:secondary { color: rgb(0 0 0 / .25)}
As shown above, creating an alias secondary
linked to an existing alias primary
with opacity /.5
is possible, and the opacity will be multiplied 0.5 * 0.5 = 0.25
.
Add color shades
Sets multiple shades for a single color.
export default { variables: { primary: { '': '#1192e8', // primary 10: '#e5f6ff', // primary-10 20: '#bae6ff', // primary-20 } }}
Apply it using color-related syntax like fill:
.
<svg class="fill:primary-20 …">20</svg>
Add colors based on modes
Add color variables in different theme modes.
export default { variables: { primary: { '': '#ff0000', // There is usually no need to give a fallback. '@light': '#fff', '@dark': '#000' } }}
Using modes for variables, you can access a single source of truth and simplify the markup.
<html class="light"> <body class="bg:#fff@light bg:#000@dark">…</body> <body class="bg:primary">…</body></html>
Generated CSS
:root { --primary: 255 0 0} .light,:root { --primary: 255 255 255} .dark { --primary: 0 0 0} .bg\:primary { background-color: rgb(var(--primary))}
By default, theme variables drive inheritance by adding .light
or .dark
to the parent element.
Override default colors
Access the same key as the preset to override default colors, like blue-5
~ blue-95
.
export default { variables: { blue: '#4589ff' }}
Use app-*
to avoid conflicts with defaults and keep blue-*
colors consistent.
export default { variables: { app: { blue: '#4589ff' // app-blue } }}
Apply custom colors for the current application.
<div class="fg:app-blue">…</div>
Generated CSS
.fg\:app-blue { color: rgb(69 137 255)}
Screens and Breakpoints
The screen in the variable is a reserved section. In addition to being used as a property value token screen-*
, it also serves as a responsive breakpoint @*
.
Apply default screen variables using any syntax, such as width
and max-width
.
<div class="w:screen-sm max-w:screen-lg">…</div>
Conditionally apply styles using default screen variables as responsive breakpoints.
<div class="font:24 font:32@sm font:48@md">…</div>
The responsive breakpoints can be flexibly used with operators, see the responsive design documentation.
Add a screen size
Add your screen size by defining variables.
export default { variables: { screen: { desktop: 1280 // screen-desktop } }}
Apply the defined screen variables anywhere:
<div class="max-w:screen-desktop mx:auto">…</div>
Generated CSS
.mx\:auto { margin-left: auto; margin-right: auto} .max-w\:screen-desktop { max-width: 80rem}
And it can be used as a responsive breakpoint:
<div class="font:24 font:48@desktop">…</div>
Generated CSS
.font\:24 { font-size: 1.5rem} @media (min-width:1280px) { .font\:48\@desktop { font-size: 3rem }}
Spacing and Sizing
The spacing and sizing system is constructed using a base unit of 4 pixels. For visual consistency, you can use the multiplier unit x
to apply spacing with the same scale.
<div class="m:1x">4px, margin: 0.25rem</div><div class="p:2x">8px, padding: 0.5rem</div><div class="w:8x">32px, width: 2rem</div><div class="gap:3x">12px, gap: 0.75rem</div><div class="size:6x">24px, width: 1.5rem; height: 1.5rem</div>
It's no longer necessary to define the spacing scale one by one as in the traditional way.
export default { variables: { spacing: { '1x': 4, '2x': 8, ..., '100x': 400 } }}
For other intermediate values, 0
, 1
, 2
, ..., we tend to use unitless tokens:
<div class="m:0">0px, margin: 0rem</div><div class="p:1">1px, padding: 0.0625rem</div><div class="w:2">2px, width: 0.125rem</div>
Add a spacing
Customize your spacing variables, in xs~xl
.
export default { variables: { spacing: { md: 20 } }}
Apply the defined spacing
variables using the inherited syntaxes like margin-top
and padding
.
<div class="mt:md p:md">…</div>
Do not use numerical values as tokens.
export default { variables: { spacing: { 1: 4, 2: 8 } }}
It can be confused with the unitless values.