Add spacing objects, typography tokens lessons and update extraction rules
New lessons in Module 11: Spacing as First-Class Objects (lesson 04) and Typography Tokens (lesson 05). Updated module overview with dual-ID system, positional IDs, and new lesson links. Tutorial 11 now includes spacing and typography steps. Module 12 lesson 01 updated with object vs spacing extraction timing rules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7e4a8e1a7f
commit
095c2ec92e
|
|
@ -0,0 +1,192 @@
|
|||
# Module 11: Conceptual Specifications
|
||||
|
||||
## Lesson 4: Spacing as First-Class Objects
|
||||
|
||||
**The invisible layer that holds everything together**
|
||||
|
||||
---
|
||||
|
||||
## The Gap Is Not Empty
|
||||
|
||||
Look at a well-designed page. Between the header and the hero. Between the cards in a grid. Between a heading and the paragraph below it.
|
||||
|
||||
That space is not "nothing." It's a design decision.
|
||||
|
||||
In WDS, **spacing is a first-class object** — it has an ID, a type, and a value, just like a button or a card.
|
||||
|
||||
---
|
||||
|
||||
## Why Spacing Gets an ID
|
||||
|
||||
Without IDs, spacing conversations sound like this:
|
||||
|
||||
> "Add more space between the trust section and the seasons section"
|
||||
|
||||
With IDs, they sound like this:
|
||||
|
||||
> "Change `hem-v-space-3xl` to `space-4xl`"
|
||||
|
||||
The second version is precise, traceable, and can be found in the design system. The first version requires the developer to figure out which space you mean.
|
||||
|
||||
---
|
||||
|
||||
## The Naming Convention
|
||||
|
||||
```
|
||||
{page}-{v|h}-{type}-{size}
|
||||
```
|
||||
|
||||
| Part | Meaning | Examples |
|
||||
|------|---------|---------|
|
||||
| `{page}` | Which page | `hem`, `nyheter`, `om-oss` |
|
||||
| `{v\|h}` | Direction | `v` = vertical, `h` = horizontal |
|
||||
| `{type}` | What kind | `space`, `separator`, `line` |
|
||||
| `{size}` | Token value | `zero`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `flex` |
|
||||
|
||||
**The ID describes WHAT the spacing IS, not what it sits between.**
|
||||
|
||||
### Examples
|
||||
|
||||
```markdown
|
||||
#### ↕ `hem-v-space-zero` — header and service menu form one continuous nav unit
|
||||
#### ↕ `hem-v-separator-2xl` — gray line, space-2xl above and below
|
||||
#### ↕ `hem-v-space-3xl` — major section boundary between seasons and footer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zero Spacing Is a Decision
|
||||
|
||||
When two objects touch with no gap, that's a deliberate design choice:
|
||||
|
||||
```markdown
|
||||
#### ↕ `hem-v-space-zero` — hero sits flush below navigation, background color shift provides visual separation
|
||||
```
|
||||
|
||||
If you don't document this, a future developer might "fix" it by adding spacing. Zero spacing says: "This is intentional. Don't add a gap."
|
||||
|
||||
---
|
||||
|
||||
## How Spacing Appears in Page Specs
|
||||
|
||||
Between each section, an explicit spacing object:
|
||||
|
||||
```
|
||||
┌──────────────────────────┐
|
||||
│ Site Header │
|
||||
├──────────────────────────┤
|
||||
│ ↕ hem-v-space-zero │ ← spacing object
|
||||
├──────────────────────────┤
|
||||
│ Service Menu │
|
||||
├──────────────────────────┤
|
||||
│ ↕ hem-v-space-zero │ ← spacing object
|
||||
├──────────────────────────┤
|
||||
│ Hero Section │
|
||||
├──────────────────────────┤
|
||||
│ ↕ hem-v-space-zero │ ← spacing object (bg color shift)
|
||||
├──────────────────────────┤
|
||||
│ About Section │
|
||||
├──────────────────────────┤
|
||||
│ ↕ hem-v-separator-2xl │ ← gray line with equal spacing
|
||||
├──────────────────────────┤
|
||||
│ Trust Cards │
|
||||
├──────────────────────────┤
|
||||
│ ↕ hem-v-space-3xl │ ← major boundary
|
||||
├──────────────────────────┤
|
||||
│ Season Cards │
|
||||
└──────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Group-Level vs. Individual Spacing
|
||||
|
||||
When all items in a grid share the same spacing, define it **on the container**:
|
||||
|
||||
```markdown
|
||||
| Grid gap | h-space-lg / v-space-lg (24px) |
|
||||
```
|
||||
|
||||
Don't create separate spacing objects between card 1 and card 2, card 2 and card 3. The grid gap handles it.
|
||||
|
||||
Individual spacing objects are for **between sections** and **non-uniform gaps**.
|
||||
|
||||
---
|
||||
|
||||
## Internal Spacing
|
||||
|
||||
Spacing inside a component (image-to-heading, heading-to-teaser inside a card) is NOT specified upfront. It's added only when the designer explicitly requests it during visual review.
|
||||
|
||||
```markdown
|
||||
<!-- Internal spacing (image->heading, heading->teaser, content padding)
|
||||
is NOT specified yet. Add here only when the designer requests it. -->
|
||||
```
|
||||
|
||||
This follows the emergent principle: don't design what hasn't been needed yet.
|
||||
|
||||
---
|
||||
|
||||
## Spacing in the Design System
|
||||
|
||||
Spacing objects go to the design system **immediately on first use** — unlike regular objects which extract on second use.
|
||||
|
||||
Why? Because spacing is relational. When you decide that a heading needs `space-xl` above a card grid, that's a universal design principle, not a page-specific detail.
|
||||
|
||||
The design system organizes patterns by spacing value:
|
||||
|
||||
```markdown
|
||||
### v-space-3xl
|
||||
| Above | Below | Why |
|
||||
|-------|-------|-----|
|
||||
| `trust-section` | `seasons-section` | Major section boundary |
|
||||
| `seasons-section` | `site-footer` | Major section boundary |
|
||||
|
||||
### v-space-zero
|
||||
| Above | Below | Why |
|
||||
|-------|-------|-----|
|
||||
| `site-header` | `service-menu` | One continuous nav unit |
|
||||
| `service-menu` | `hero` | Flush below navigation |
|
||||
```
|
||||
|
||||
As more pages are designed, each spacing value accumulates more situations. The pattern table grows from real decisions.
|
||||
|
||||
---
|
||||
|
||||
## How Many Spacing Objects Per Page?
|
||||
|
||||
On a typical homepage with 8 sections:
|
||||
|
||||
- **6 spacing objects** between sections
|
||||
- **4 sections** with internal spacing properties (padding, grid gap)
|
||||
- **10 total** spacing declarations
|
||||
|
||||
That's lean. One or two per section boundary. Not dozens.
|
||||
|
||||
---
|
||||
|
||||
## The Communication Pattern
|
||||
|
||||
Always use token names when discussing spacing:
|
||||
|
||||
```
|
||||
BAD: "Add 48 pixels above the footer"
|
||||
GOOD: "Change hem-v-space-3xl to space-4xl above the footer"
|
||||
```
|
||||
|
||||
This builds a shared vocabulary. Over time, the designer and developer both think in tokens.
|
||||
|
||||
---
|
||||
|
||||
## What's Next
|
||||
|
||||
In the next module, you'll learn how patterns emerge across pages and when to extract them into reusable components.
|
||||
|
||||
---
|
||||
|
||||
**[Continue to Lesson 5: Typography Tokens →](lesson-05-typography-tokens.md)**
|
||||
|
||||
---
|
||||
|
||||
[← Back to Lesson 3](lesson-03-element-state-specifications.md) | [Back to Module Overview](module-11-conceptual-specifications-overview.md)
|
||||
|
||||
*Part of Module 11: Conceptual Specifications*
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
# Module 11: Conceptual Specifications
|
||||
|
||||
## Lesson 5: Typography Tokens — Size Is Not Structure
|
||||
|
||||
**Decoupling visual size from semantic meaning**
|
||||
|
||||
---
|
||||
|
||||
## The Problem
|
||||
|
||||
Most design systems conflate two things:
|
||||
|
||||
- **Visual size** — how big text looks
|
||||
- **Semantic level** — what the text means (H1, H2, H3, p)
|
||||
|
||||
This creates rigid rules like "H1 is always 48px" or "H2 is always 32px." But reality doesn't work that way.
|
||||
|
||||
A landing page H1 might be a serif display font at 56px italic.
|
||||
An admin page H1 might be clean sans-serif at 20px medium.
|
||||
A sidebar H2 might be 14px.
|
||||
|
||||
The semantic level is for accessibility and SEO. The visual token is for hierarchy.
|
||||
|
||||
---
|
||||
|
||||
## The WDS Approach
|
||||
|
||||
Two independent systems:
|
||||
|
||||
### Heading Scale (Visual Size)
|
||||
|
||||
| Token | Size | Weight | Example Use |
|
||||
|-------|------|--------|-------------|
|
||||
| `heading-xxs` | 14px | 700 | Smallest sub-headers |
|
||||
| `heading-xs` | 16px | 700 | Minor headings, labels |
|
||||
| `heading-sm` | 18px | 700 | Card sub-headings |
|
||||
| `heading-md` | 20px | 800 | Card headings |
|
||||
| `heading-lg` | 24px | 800 | Section sub-headers |
|
||||
| `heading-xl` | 30px | 900 | Section headers |
|
||||
| `heading-2xl` | 36px | 900 | Major section headers |
|
||||
| `heading-3xl` | 44px | 900 | Hero headings (tablet) |
|
||||
| `heading-4xl` | 56px | 900 | Hero headings (desktop) |
|
||||
|
||||
### Semantic Level (Document Structure)
|
||||
|
||||
`<h1>`, `<h2>`, `<h3>`, `<p>` — these define the document outline for accessibility and SEO.
|
||||
|
||||
### How They Combine
|
||||
|
||||
```html
|
||||
<h2 class="text-heading-lg md:text-heading-xl lg:text-heading-2xl">
|
||||
Our Services
|
||||
</h2>
|
||||
```
|
||||
|
||||
This `<h2>` is `heading-lg` on mobile, `heading-xl` on tablet, `heading-2xl` on desktop. The semantic level stays H2 on all devices. The visual size adapts.
|
||||
|
||||
---
|
||||
|
||||
## The Responsive Scaling Rule
|
||||
|
||||
Step up one token size per breakpoint:
|
||||
|
||||
```
|
||||
Mobile: heading-lg (24px)
|
||||
Tablet: heading-xl (30px)
|
||||
Desktop: heading-2xl (36px)
|
||||
```
|
||||
|
||||
In code:
|
||||
```html
|
||||
<h2 class="text-heading-lg md:text-heading-xl lg:text-heading-2xl">
|
||||
```
|
||||
|
||||
In specifications:
|
||||
```markdown
|
||||
| Visual size | heading-lg / heading-xl / heading-2xl |
|
||||
```
|
||||
|
||||
Always use token names — never arbitrary pixel values per breakpoint.
|
||||
|
||||
---
|
||||
|
||||
## Body Type Scale
|
||||
|
||||
The same principle applies to body text:
|
||||
|
||||
| Token | Size | Weight | Usage |
|
||||
|-------|------|--------|-------|
|
||||
| `text-body` | 16px | 400 | Body text |
|
||||
| `text-body-small` | 14px | 400 | Captions, metadata |
|
||||
| `text-body-large` | 18px | 400 | Lead paragraphs |
|
||||
| `text-label` | 14px | 600 | Labels, badges |
|
||||
| `text-phone` | 24px | 700 | Phone number CTA |
|
||||
|
||||
---
|
||||
|
||||
## Why Tokens Beat Pixel Values
|
||||
|
||||
### 1. Single Point of Change
|
||||
|
||||
Bump `heading-xl` from 30px to 32px and every section header on the site adjusts. No hunting through files.
|
||||
|
||||
### 2. Shared Vocabulary
|
||||
|
||||
"Change the heading from `heading-lg` to `heading-xl`" is precise. "Make it bigger" is not.
|
||||
|
||||
### 3. Consistent Hierarchy
|
||||
|
||||
Tokens enforce a scale. You can't accidentally use 31px when the scale goes 30, 36, 44.
|
||||
|
||||
### 4. Responsive by Default
|
||||
|
||||
Each token has responsive variants built in. No reinventing breakpoint behavior per element.
|
||||
|
||||
---
|
||||
|
||||
## When Tokens Emerge
|
||||
|
||||
Don't create the full type scale before building any pages.
|
||||
|
||||
Build pages first. Notice that you keep using the same sizes. Extract the scale from real usage.
|
||||
|
||||
On the Kalla project, the heading scale emerged after the homepage was built and refined through browser review. The same heading sizes appeared 3+ times in different sections — that's when they became tokens.
|
||||
|
||||
---
|
||||
|
||||
## Specifying Typography in Page Specs
|
||||
|
||||
```markdown
|
||||
### Section Heading
|
||||
|
||||
**OBJECT ID:** `hem-trust-heading`
|
||||
**DS TYPE:** `section-heading`
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Tag | h2 |
|
||||
| Visual size | heading-xl / heading-xl / heading-2xl |
|
||||
| Font family | font-headline (Inter) |
|
||||
| Font weight | 900 |
|
||||
| Color | text-primary (#141414) |
|
||||
```
|
||||
|
||||
Notice: the semantic tag (`h2`) and the visual size (`heading-xl`) are independent. The same component template can be used for an H2 on one page and an H3 on another.
|
||||
|
||||
---
|
||||
|
||||
## What's Next
|
||||
|
||||
You now understand the three invisible specification layers: spacing objects (Lesson 4), typography tokens (this lesson), and the dual-ID system that connects them to the design system (Module 12).
|
||||
|
||||
---
|
||||
|
||||
[← Back to Lesson 4](lesson-04-spacing-objects.md) | [Back to Module Overview](module-11-conceptual-specifications-overview.md)
|
||||
|
||||
*Part of Module 11: Conceptual Specifications*
|
||||
|
|
@ -99,16 +99,40 @@ Specifications use consistent terminology:
|
|||
|
||||
## IDs Are the Key
|
||||
|
||||
Every object gets a unique ID:
|
||||
Every object has two IDs:
|
||||
|
||||
1. **Instance ID** — unique on the page: `hem-trust-cards:pos-1`
|
||||
2. **DS Type** — defined in the design system: `article-card`
|
||||
|
||||
The Instance ID tells you WHERE this specific object is. The DS Type tells you WHAT kind of object it is.
|
||||
|
||||
```markdown
|
||||
### Trust Card 1
|
||||
|
||||
**OBJECT ID:** `hem-trust-cards:pos-1`
|
||||
**DS TYPE:** `article-card`
|
||||
```
|
||||
|
||||
### Positional IDs for Lists
|
||||
|
||||
When a page has multiple instances of the same component, use positional identifiers:
|
||||
|
||||
```
|
||||
Page: P01-signup-page
|
||||
Section: P01-S01-hero-section
|
||||
Widget: P01-S02-W01-signup-form
|
||||
Card: P01-S03-C01-feature-card
|
||||
Element: P01-S02-W01-E01-email-field
|
||||
hem-trust-cards:pos-1
|
||||
hem-trust-cards:pos-2
|
||||
hem-trust-cards:pos-3
|
||||
```
|
||||
|
||||
Child elements use colon-separated hierarchy:
|
||||
|
||||
```
|
||||
hem-trust-cards:pos-1:image
|
||||
hem-trust-cards:pos-1:heading
|
||||
hem-trust-cards:pos-1:teaser
|
||||
```
|
||||
|
||||
Use positional IDs (`pos-1`, `pos-2`) instead of semantic names when content order can change dynamically.
|
||||
|
||||
**Why IDs matter:**
|
||||
|
||||
1. **Traceability** — From spec → code → test
|
||||
|
|
@ -117,6 +141,7 @@ Element: P01-S02-W01-E01-email-field
|
|||
4. **Accessibility** — Reference specific elements for ARIA
|
||||
5. **Analytics** — Track interactions precisely
|
||||
6. **Testing** — Target elements for automation
|
||||
7. **Design System** — Link page instances to reusable types
|
||||
|
||||
**Without IDs, specifications are just documentation. With IDs, they're implementation maps.**
|
||||
|
||||
|
|
@ -410,6 +435,12 @@ Deep dive on specifying sections (placement, responsive behavior) and widgets (r
|
|||
**Lesson 3: Element & State Specifications**
|
||||
Complete element specifications with all states, exact content, ARIA attributes, edge cases, and translations
|
||||
|
||||
**Lesson 4: Spacing as First-Class Objects**
|
||||
Every gap between sections gets an ID, a type, and a value — the invisible layer that holds everything together
|
||||
|
||||
**Lesson 5: Typography Tokens — Size Is Not Structure**
|
||||
Decouple visual size from semantic meaning. An H2 can be `heading-xl` on the homepage and `heading-sm` in a sidebar.
|
||||
|
||||
**Tutorial: Specify Your Pages**
|
||||
Hands-on practice with Freya creating complete specifications
|
||||
|
||||
|
|
@ -440,6 +471,12 @@ Deep dive on Layers 2 & 3 of the hierarchy
|
|||
### [Lesson 3: Element & State Specifications](lesson-03-element-state-specifications.md)
|
||||
Deep dive on Layers 4 & 5 — Complete implementation details
|
||||
|
||||
### [Lesson 4: Spacing as First-Class Objects](lesson-04-spacing-objects.md)
|
||||
The invisible layer — every gap gets an ID, a type, and a value
|
||||
|
||||
### [Lesson 5: Typography Tokens — Size Is Not Structure](lesson-05-typography-tokens.md)
|
||||
Decouple visual size from semantic meaning
|
||||
|
||||
---
|
||||
|
||||
## Tutorial
|
||||
|
|
|
|||
|
|
@ -344,7 +344,44 @@ Summary:
|
|||
|
||||
---
|
||||
|
||||
## Step 8: Review Complete Specification (5 min)
|
||||
## Step 8: Add Spacing Objects (5 min)
|
||||
|
||||
### Freya guides the invisible layer:
|
||||
|
||||
> "Now let's specify the spacing between sections. Every gap needs an ID."
|
||||
|
||||
**You work through the page sections:**
|
||||
|
||||
```markdown
|
||||
## Spacing Objects
|
||||
|
||||
#### ↕ `signup-v-space-zero` — header sits flush against form section
|
||||
#### ↕ `signup-v-space-xl` — comfortable gap between form and trust section
|
||||
#### ↕ `signup-v-space-lg` — standard gap between trust section and footer
|
||||
```
|
||||
|
||||
**Freya reminds:**
|
||||
> "Zero spacing is a design decision too — document it so nobody 'fixes' it later."
|
||||
|
||||
### Typography tokens:
|
||||
|
||||
> "Let's also specify the heading sizes using tokens, not pixels."
|
||||
|
||||
```markdown
|
||||
### Headline
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Tag | h1 |
|
||||
| Visual size | heading-xl / heading-2xl / heading-3xl |
|
||||
| Font weight | 900 |
|
||||
```
|
||||
|
||||
**Freya explains:**
|
||||
> "The semantic tag (h1) and the visual size (heading-xl) are independent. The h1 tells screen readers this is the page title. The token controls how big it looks."
|
||||
|
||||
---
|
||||
|
||||
## Step 9: Review Complete Specification (5 min)
|
||||
|
||||
### Freya presents the full document:
|
||||
|
||||
|
|
@ -370,7 +407,7 @@ If yes, you're done. If not, identify what's missing.
|
|||
|
||||
---
|
||||
|
||||
## Step 9: Save and Organize (2 min)
|
||||
## Step 10: Save and Organize (2 min)
|
||||
|
||||
### Save the specification:
|
||||
|
||||
|
|
|
|||
|
|
@ -48,11 +48,27 @@ Shared vocabulary with developers.
|
|||
|
||||
## When to Extract
|
||||
|
||||
Not everything should be a component. Look for:
|
||||
Not everything should be a component. And **objects and spacing have different extraction timing:**
|
||||
|
||||
### Objects: Extract on Second Use
|
||||
|
||||
The first time a button or card appears, it's a one-off — it stays inline in the page spec. The second time the same pattern appears (same states, same behavior), it's a real pattern. Extract it to the design system.
|
||||
|
||||
First use = one-off. Second use = pattern. Extract.
|
||||
|
||||
### Spacing: Extract Immediately
|
||||
|
||||
Spacing extracts on **first use** — no waiting for a second occurrence.
|
||||
|
||||
Why? Because spacing is relational. When you decide that a heading needs `space-xl` above a card grid, that's a universal design principle — not a page-specific detail. It applies everywhere that pair of object types appears.
|
||||
|
||||
### The Decision Checklist
|
||||
|
||||
For objects, look for:
|
||||
|
||||
**Appears more than once**
|
||||
|
||||
Once is an instance. Twice or more is a pattern worth considering.
|
||||
Once is an instance. Twice or more is a pattern worth extracting.
|
||||
|
||||
**Consistent behavior**
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue