HTML/CSS - 29
HTML/CSS - 29: Building a Design System
A design system is a collection of reusable design decisions and components that help a website stay consistent as it grows.
Instead of choosing a new color, spacing value, or button style every time you add something, you define a small set of shared rules and reuse them.
You have already worked with CSS variables and reusable components. In this lesson, you will combine those ideas into a small design system with design tokens, typography, spacing, buttons, and cards.
Your challenge: Build a small design system that keeps several different components visually consistent.
What is a design token?
A design token is a named value that represents part of the visual system.
For example: --color-accent stores an accent color, while --space-large stores a larger spacing value.
The name describes the purpose of the value instead of the exact number or color.
That means: padding: var(--space-large); is easier to understand than seeing an unexplained value such as padding: 24px; repeated throughout a large stylesheet.
Color tokens:
Try to avoid creating a separate color for every element. Instead, define a small palette and reuse it.
For example: --color-bg can be the page background, --color-surface can be used for cards, and --color-muted can be used for secondary text or borders.
Spacing tokens:
Consistent spacing helps a design feel organized.
Instead of using values such as 13px, 19px, and 27px randomly, you can create a small spacing scale.
For example: --space-small, --space-medium, and --space-large.
Typography tokens:
The same idea can be used for text sizes. A small set of reusable sizes can help headings, body text, labels, and badges feel related.
For example: font-size: var(--text-small); can be useful for a badge or small label.
Build the button component:
Start with a shared .btn class that controls padding, border radius, font weight, and cursor behavior.
Then create: .btn-primary and .btn-secondary for the visual differences.
The shared class should contain the rules that both versions need.
Build the card:
Use the surface color, spacing tokens, border color, and large radius token to create a reusable card.
Because all of those values come from :root, the component stays connected to the rest of the design system.
Build a badge:
A badge is a small label that can identify a status or category. Try using: display: inline-block;, a small font token, padding, and a border radius.
Experiment: Change only --color-muted.
If several components use that token, multiple parts of the page should update together.
Then change: --radius-large from 12px to 2px.
The page should immediately feel sharper and less rounded without changing the card rule itself.
What makes this different from Lesson 21?
CSS architecture focuses on organizing reusable styles and variables. A design system goes one step further by defining a deliberate set of shared visual rules that components follow.
The tokens, components, and conventions work together as one system.
Documentation matters too:
A real design system often explains how components should be used. For example, documentation might explain when to use a primary button instead of a secondary one.
Even simple CSS comments can help document your system: /* Primary action button */
Avoid creating too many tokens:
If every value becomes its own variable, the system can become harder to understand instead of easier. Create tokens for values that repeat or represent an intentional design decision.
Good design-system habit: Consistency matters more than having dozens of components. Start with a small set of useful tokens and reusable patterns, then expand the system only when the project actually needs more.
👀 Show Solution
<style>
:root {
--color-bg: #000000;
--color-surface: #111111;
--color-text: #dddddd;
--color-muted: #8A8A8A;
--color-accent: #ffffff;
--space-small: 8px;
--space-medium: 16px;
--space-large: 24px;
--radius-small: 6px;
--radius-large: 12px;
--text-small: 0.875rem;
--text-normal: 1rem;
--text-large: 1.5rem;
}
body {
background-color: var(--color-bg);
color: var(--color-text);
}
.btn {
padding:
var(--space-small)
var(--space-medium);
border-radius: var(--radius-small);
font-weight: bold;
cursor: pointer;
}
.btn-primary {
background-color: var(--color-accent);
color: var(--color-bg);
border: 2px solid var(--color-accent);
}
.btn-secondary {
background-color: transparent;
color: var(--color-text);
border: 2px solid var(--color-muted);
}
.card {
max-width: 500px;
margin-top: var(--space-large);
padding: var(--space-large);
background-color: var(--color-surface);
border:
2px solid
var(--color-muted);
border-radius: var(--radius-large);
}
.card h2 {
font-size: var(--text-large);
}
.badge {
display: inline-block;
padding:
4px
var(--space-small);
margin-bottom: var(--space-small);
color: var(--color-bg);
background-color: var(--color-muted);
border-radius: var(--radius-small);
font-size: var(--text-small);
font-weight: bold;
}
</style>
<section class="card">
<span class="badge">New</span>
<h2>Signal Archive</h2>
<p>
A fictional collection of unusual signals
recorded from distant places.
</p>
<button class="btn btn-primary">
Explore
</button>
<button class="btn btn-secondary">
Details
</button>
</section>The colors, spacing, text sizes, and border radiuses are stored as shared design tokens. The button, card, and badge components then reuse those tokens instead of inventing separate values.
Because the components depend on the same system, changing one token can update several parts of the interface while keeping the overall design consistent.
