Shared Design System
Learning Website: Framework & Architecture
Chapter 4 · The Shared Design System
If the site becomes several sites, they still have to look like members of one family. A visitor who moves from the languages site to the programming site should not feel they have changed websites, and you should not have to change a colour in fifty places. This chapter looks at what the fragments really contain, chooses a design approach that does not require rewriting thousands of files, and sets up the pieces: tokens, shared components, and a safe order for loading them.
What the Fragments Contain Today
Every fragment carries its own <style> block, scoped under its own wrapper class. That
scoping rule is deliberate, because it stops one fragment's styles leaking into another. The price is
repetition. Measuring a few courses gives these results:
| Folder | Files | Distinct colours | CSS as share of file bytes | Accent colour |
|---|---|---|---|---|
| Hungarian Basic 3 | 12 | 14 | 13% | #5aa469 |
| German Basic 1 | 12 | 14 | 17% | #e0a82e |
| Japanese Basic 1 | 12 | 14 | 17% | #d64550 |
| Apache In Depth | 10 | 19 | 30% | #f0938a |
| Sidebar: programming | 30 | 16 | 12% | #6ee7b7 |
| Django rebuild | 12 | 21 | 32% | #44b78b |
Four findings stand out:
- The three language courses share the same palette. Surfaces
#1a1d27, borders#2a2d3a, text#e2e4ec, muted#a0a4b8and the purple speaker colour#7c5cbfare identical. Only the accent changes. - There are two neutral families. The technical courses use a different set (
#161b22surfaces,#30363dborders,#c9d1d9text,#8b949emuted), with their own accent per course. - The same CSS is copied into every chapter. A colour used nine times in one chapter appears 108 times in a 12-chapter course.
- CSS is 12% to 32% of each file. A visitor downloads the same styling again on every chapter.
Three Ways to Share Design
| Approach | How it works | Verdict |
|---|---|---|
| A. Leave it as it is | Each fragment keeps its own CSS. Sites only share the surrounding layout. | Nothing to migrate, but the repetition stays and a brand change means editing every file. |
| B. One shared stylesheet, all at once | Strip the CSS from every fragment and rely on shared rules. | Cleanest result, but a very large rewrite that touches every file and risks broken pages. |
| C. Tokens and shared components, gradually | Define colours and spacing as variables. Provide shared component styles as defaults. Fragments keep working and are migrated when convenient. | Recommended: safe at every step. |
This course follows approach C. New content uses the shared layer, and old content keeps its own rules until it is rewritten or migrated by script.
Design Tokens
A token is a named value: --surface instead of #1a1d27. In CSS
the natural way to hold tokens is custom properties (variables). They cascade, so you can set a different
value for a part of the page, which is exactly what per-language accents need.
Two neutral families can stay as they are for now. Unifying them into one is a design decision for later; tokens make it a small change when you choose to do it, because every use reads the variable.
A safe way to introduce the variable
Existing fragments hard-code their accent. A script can replace each occurrence inside the style block
only with var(--accent, #5aa469). The second argument is a fallback: if the variable is not
defined, the browser uses the old colour, so the page looks exactly as before. That makes each file's
migration independently safe (Exercise 2).
Shared Components
The fragments already use the same class names for the same ideas, which is what makes a shared layer possible:
| Group | Classes in common use |
|---|---|
| Page header | .lesson-head, .course-name, .chapter-sub |
| Callouts | .tip-box, .warn-box, .finding-box |
| Code | .code-block, .code-block-wrap, .copy-btn |
| Tables | .compare-table, .vocab-table |
| Exercises | .challenge-block, .ch-num, .ch-body, .ch-link, .quick-ref |
| Language lessons | .dialog-grid, .dialog-card, .vocab-table, .tip-box |
A shared components.css styles these once, using the tokens. Fragments that still carry their
own rules for the same classes keep winning, as the next section explains.
Who Wins When Rules Collide
The existing scoping rule has a useful side effect. A fragment's rule such as
.hu-lesson .tip-box is more specific (two classes) than a shared .tip-box (one
class), so the fragment's own rule wins. If you write the shared rule with the same specificity, for
example [data-site=languages] .tip-box, the two tie, and the later one in the document wins.
The layout's stylesheet is in <head> and the fragment's <style> is
inside the body, so the fragment still wins. Both effects protect old pages during a migration.
!important. It spreads, because the next rule that
needs to override it needs one too. Fix a clash by changing specificity or by deleting the old rule.
Load order is therefore: tokens, then base, then components, then the fragment's own style. Exercise 3 writes the token file and checks the specificity rules with a small script.
Per-Area Accents
Colour already tells visitors where they are. These accents are in use today, with the contrast each one
gives against the language surface #1a1d27:
| Area | Accent | Contrast |
|---|---|---|
| Hungarian | #5aa469 | 5.56 |
| German | #e0a82e | 7.85 |
| Japanese | #d64550 | 3.86 |
| French | #4f8ef7 | 5.24 |
| Links pages | #38bdf8 | 7.85 |
| Sidebar lessons | #fbbf24 | 10.07 |
| Cheat sheets | #6ee7b7 | 11.03 |
WCAG level AA asks for a contrast ratio of at least 4.5 for normal-size text. Every accent passes except the
Japanese red, at 3.86. It is fine for borders, buttons and large headings, but weak for small coloured text.
The right place to fix this is the token file, for instance with a separate lighter
--accent-text for that language, not in each chapter (Exercise 3, part D).
Fonts, Printing and PDFs
- Fonts are tokens too. The language lessons use a serif body font (Georgia) and the technical ones use the system sans-serif. Put each in a variable such as
--font-body. - Web fonts and origins. If a font is loaded from another subdomain, the browser requires CORS headers (Learning Website: Framework & Architecture 1). The simplest options are system fonts, or self-hosting the same font files on every site.
- The PDF builders render these same fragments. Any change to the shared layer changes the PDFs too, and the copy buttons are hidden for print by an
@media printrule. After a design change, rebuild one chapter PDF and look at it before trusting the change.
Where the Design System Lives
The tokens, base and components are one small unit, shared by every site and versioned together. In a framework this becomes a package or a static folder:
Each site includes the same four files. The Django course (Learning Website with Django 5) serves them as static files, and the Next.js course (Learning Website with Next.js 5) imports them from a shared workspace package. A change in one place reaches every site on its next build, so treat the design system like code: review it and test it before release.
Hands-On Exercises
Write palette.py, which reports for each folder of fragments the number of files, the number of distinct colours in the style blocks, the share of the file bytes that is CSS, and the most common colours. Run it on several courses from different areas and write down what is shared and what differs.
Write a script that replaces a fragment's accent colour, inside its <style> blocks only, with var(--accent, <the same colour>). Have it report the number of replacements and check that the braces are still balanced and the markup outside the style block is unchanged. Run it without modifying the original file.
Write a tokens.css for the two neutral families and the language accents. Then use a small script to compare the specificity of a shared .tip-box rule and a fragment's .hu-lesson .tip-box rule, state the load order, and check the contrast of every accent against the language surface.
Chapter 4 Quick Reference
- Every fragment carries its own scoped CSS: 12% to 32% of file size, copied into every chapter
- The language courses share one palette and differ only in the accent colour; the technical courses use a second neutral family
- Approach: tokens plus shared components, migrated gradually (not a one-off rewrite)
- Tokens are CSS custom properties; set them per family or per wrapper so accents can differ by area
- Migrate safely with
var(--accent, #oldcolour): the fallback keeps old pages unchanged - A fragment's
.wrapper .classrule beats a shared.classrule; on a tie the later one (the fragment's style) wins - Load order: tokens, base, components, then the fragment's own style
- Avoid
!important; fix clashes with specificity or by deleting the old rule - Check contrast: WCAG AA needs 4.5 for normal text, and the Japanese red
#d64550scores 3.86 - PDF builders use the same HTML, so rebuild a PDF to check after a design change