- templates/index.html — landing/hero page with feature cards - templates/docs.html — docs layout with sidebar nav, content, and TOC - templates/article.html — long-form prose with code blocks and blockquotes - templates/dashboard.html — stats grid with system status panels - templates/tasks.html — vault-style task tracker with data-task attributes All templates use semantic HTML only, data-layout attributes for structure, zero class= for layout, and link to dist/asw.css.
150 lines
6.4 KiB
HTML
150 lines
6.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Understanding CSS Custom Properties — ASW Blog</title>
|
|
<meta name="description" content="A deep dive into CSS custom properties, the oklch colour space, and building design tokens with native CSS.">
|
|
<link rel="stylesheet" href="../dist/asw.css">
|
|
</head>
|
|
<body>
|
|
|
|
<!-- Site navigation bar -->
|
|
<nav data-layout="spread">
|
|
<a href="index.html" aria-label="ASW home"><strong>ASW</strong></a>
|
|
<span data-layout="row">
|
|
<a href="docs.html">Docs</a>
|
|
<a href="article.html" aria-current="page">Blog</a>
|
|
<a href="dashboard.html">Dashboard</a>
|
|
<a href="tasks.html">Tasks</a>
|
|
</span>
|
|
</nav>
|
|
|
|
<!-- Article header -->
|
|
<header>
|
|
<p data-layout="row">
|
|
<time datetime="2026-06-01">June 1, 2026</time>
|
|
<span>by <a href="#">ASW Team</a></span>
|
|
<span>—</span>
|
|
<span>8 min read</span>
|
|
</p>
|
|
<h1>Understanding CSS Custom Properties</h1>
|
|
<p>A deep dive into native CSS design tokens, the <code>oklch</code> colour space, and building a token system without preprocessors.</p>
|
|
</header>
|
|
|
|
<!-- Prose content -->
|
|
<article data-layout="prose">
|
|
|
|
<h2>Why Custom Properties?</h2>
|
|
<p>CSS custom properties (often called CSS variables) let you store values and reuse them throughout your stylesheet. Unlike preprocessor variables (<code>$</code> in Sass or Less), custom properties are live — they cascade, can be overridden at any level, and can be changed at runtime.</p>
|
|
|
|
<blockquote>
|
|
<p>"Custom properties are to design tokens what functions are to programming — they give you a single source of truth that ripples through the entire system."</p>
|
|
</blockquote>
|
|
|
|
<p>When you define a value once as a custom property, every reference to it updates automatically when the property changes. This is the foundation of a maintainable design system.</p>
|
|
|
|
<h2>The oklch Colour Space</h2>
|
|
<p>Traditional <code>rgb</code> and <code>hsl</code> colour spaces are device-dependent and perceptually uneven. The <code>oklch</code> colour space, introduced in CSS Color Level 4, is designed for human perception — a 10% lightness shift looks like a 10% lightness shift, regardless of the hue.</p>
|
|
|
|
<pre><code>/* Traditional RGB — hard to reason about */
|
|
--accent: #4a6cf7;
|
|
|
|
/* oklch — perceptually uniform, easy to tweak */
|
|
--accent: oklch(65% 0.15 250);</code></pre>
|
|
|
|
<p>The three components of oklch are:</p>
|
|
<ul>
|
|
<li><strong>L</strong> — Lightness (0% to 100%)</li>
|
|
<li><strong>C</strong> — Chroma or saturation (0 to ~0.4)</li>
|
|
<li><strong>H</strong> — Hue (0 to 360 degrees)</li>
|
|
</ul>
|
|
|
|
<h3>Why This Matters for Design Systems</h3>
|
|
<p>Because oklch uses a polar coordinate system (like HSL), you can rotate hues while keeping perceptual lightness constant. This makes generating colour scales, accent colours, and dark mode variants straightforward.</p>
|
|
|
|
<pre><code>:root {
|
|
--palette-hue: 250; /* blue-violet */
|
|
--palette-chroma: 0.15;
|
|
|
|
--accent: oklch(65% var(--palette-chroma) var(--palette-hue));
|
|
--accent-hover: oklch(72% var(--palette-chroma) var(--palette-hue));
|
|
}</code></pre>
|
|
|
|
<h2>Building a Token System</h2>
|
|
<p>A design token system organises custom properties into semantic layers:</p>
|
|
|
|
<ol>
|
|
<li><strong>Primitives</strong> — raw values (sizes, colours, fonts)</li>
|
|
<li><strong>Aliases</strong> — semantic names mapped to primitives</li>
|
|
<li><strong>Component tokens</strong> — role-specific values</li>
|
|
</ol>
|
|
|
|
<p>For example, a spacing scale starts with raw sizes:</p>
|
|
|
|
<pre><code>--size-1: 0.25rem; /* 4px */
|
|
--size-2: 0.5rem; /* 8px */
|
|
--size-3: 1rem; /* 16px */</code></pre>
|
|
|
|
<p>Then semantic aliases map those sizes to their roles:</p>
|
|
|
|
<pre><code>--space-1: var(--size-1); /* tiny gap */
|
|
--space-2: var(--size-2); /* tight gap */
|
|
--space-4: var(--size-3); /* standard gap */</code></pre>
|
|
|
|
<h2>Live Reload in the Browser</h2>
|
|
<p>One of the superpowers of custom properties is live editing. Open your browser's dev tools, change a token value in <code>:root</code>, and watch every element that uses it update in real time.</p>
|
|
|
|
<pre><code>/* Change this in dev tools and see the whole page shift */
|
|
:root {
|
|
--palette-hue: 200; /* shift from blue-violet to blue */
|
|
}</code></pre>
|
|
|
|
<h2>Common Pitfalls</h2>
|
|
<p>Custom properties are powerful, but they come with some gotchas:</p>
|
|
|
|
<ul>
|
|
<li><strong>Fallback values</strong> — always provide a fallback: <code>var(--custom, fallback)</code></li>
|
|
<li><strong>Inheritance</strong> — custom properties inherit by default. Use <code>@property</code> for controlled behaviour.</li>
|
|
<li><strong>Animation</strong> — not all custom property types can be animated without <code>@property</code></li>
|
|
<li><strong>Performance</strong> — thousands of unique custom properties in a single scope can slow repaints</li>
|
|
</ul>
|
|
|
|
<h2>Conclusion</h2>
|
|
<p>CSS custom properties, combined with the <code>oklch</code> colour space, give you everything you need for a modern design token system — no preprocessor required. It's more verbose in places, but the trade-off is runtime flexibility, browser-native live editing, and zero build dependencies.</p>
|
|
|
|
<section>
|
|
<h3>Footnotes</h3>
|
|
<ol>
|
|
<li id="fn1">The <code>oklch</code> specification is part of CSS Color Module Level 4. <a href="https://www.w3.org/TR/css-color-4/" target="_blank" rel="noopener">Read the spec</a>.</li>
|
|
<li id="fn2">Browser support for oklch is excellent — all modern browsers support it as of 2024. <a href="https://caniuse.com/css-oklch" target="_blank" rel="noopener">Check CanIUse</a>.</li>
|
|
</ol>
|
|
</section>
|
|
|
|
<hr>
|
|
|
|
<!-- Prev/Next navigation -->
|
|
<nav data-role="prev-next">
|
|
<a href="docs.html" rel="prev">
|
|
<small>← Previous</small>
|
|
<span>Documentation</span>
|
|
</a>
|
|
<a href="dashboard.html" rel="next">
|
|
<small>Next →</small>
|
|
<span>Dashboard</span>
|
|
</a>
|
|
</nav>
|
|
|
|
</article>
|
|
|
|
<!-- Footer -->
|
|
<footer data-layout="spread">
|
|
<small>© 2026 Agentic Semantic Web</small>
|
|
<nav data-layout="row">
|
|
<a href="docs.html">Docs</a>
|
|
<a href="https://github.com/agentic-semantic-web/asw" target="_blank" rel="noopener">GitHub</a>
|
|
</nav>
|
|
</footer>
|
|
|
|
</body>
|
|
</html>
|