# CSS Variables & Architecture

Custom properties and thoughtful architecture make large projects maintainable. This chapter explores modern variable techniques, the @property rule, theming strategies, and methodologies like BEM and ITCSS.

# Table of Contents

# Custom Properties Fundamentals

Custom properties (variables) allow you to store values and reuse them. They obey the cascade and can be updated at runtime. Their real power emerges when used with fallback values and context-specific overrides.

:root {
  --spacing-unit: .5rem;
  --radius: .25rem;
  --accent-hue: 200deg;
}

.box {
  padding: var(--spacing-unit);
  border-radius: var(--radius);
  background: hsl(var(--accent-hue) 70% 50%);
}
.box.special {
  --accent-hue: 340deg;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="box">Default accent hue</div>
<div class="box special">Override accent hue</div>
1
2

Variables can even store complex values like gradients or lists. Use fallback syntax (var(--name, fallback)) for robustness.

# @property Registration

The @property rule from the CSS Houdini API registers custom properties with type checking, default values, and defines whether they are inherited【460321113036012†L186-L194】. It enables custom properties to animate and be parsed correctly by the browser.

@property --rotate {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

.spin {
  --rotate: 0deg;
  animation: rotate 3s infinite linear;
}
@keyframes rotate {
  to { --rotate: 1turn; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="spin">Spinning element using registered property</div>
1

The registration ensures the browser knows the type (<angle>), so it can interpolate values correctly during animations and transitions【460321113036012†L186-L194】.

# Theming & Design Tokens

Design tokens store a set of variables representing colors, spacings, typography, and component values. Organize tokens using descriptive names and hierarchical namespaces. For theming, override tokens at the root or nearest context.

:root {
  /* Base theme */
  --color-bg: #fff;
  --color-text: #222;
  --color-accent: #0070f3;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-bg: #121212;
    --color-text: #eee;
    --color-accent: #3897ff;
  }
}

.btn {
  background: var(--color-accent);
  color: var(--color-bg);
  padding: .5rem 1rem;
  border-radius: var(--radius, .25rem);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<button class="btn">Themed Button</button>
1

Tokens can be exported to JavaScript or design tools to keep brand palettes consistent across platforms.

# Naming Conventions & Methodologies

Robust naming is critical. Methodologies like BEM (Block, Element, Modifier) and ITCSS (Inverted Triangle CSS) provide structure. Use BEM for component classes (e.g., .card__title--highlight) and ITCSS to order layers from generic to specific (settings > tools > objects > components > utilities).

/* BEM example */
.card { /* block */ }
.card__title { /* element */ }
.card--highlight { /* modifier */ }

/* ITCSS folder organization */
@import 'settings/colors.css';
@import 'tools/mixins.css';
@import 'objects/container.css';
@import 'components/button.css';
@import 'utilities/gap.css';
1
2
3
4
5
6
7
8
9
10
11

# Cascade Layers & Scope

Cascade layers (@layer) group rules into named priority layers. Combined with @scope, you can define where certain styles apply. Layers assist with dependency management and ensure third-party styles don’t inadvertently override your base styles.

@layer reset, base, components;

@layer base {
  :scope {
    font-family: system-ui, sans-serif;
    line-height: 1.5;
  }
}

@layer components {
  .button { display: inline-block; padding: .5rem 1rem; border-radius: var(--radius); }
}
1
2
3
4
5
6
7
8
9
10
11
12
<div class="button">Scoped Button</div>
1

The @scope rule (experimental) limits where styles apply to avoid bleeding across unrelated sections.

# Gotchas & Best Practices

  • Keep variable names semantic, not presentational (e.g., --color-primary instead of --blue-500).
  • Register animatable properties with @property for smooth interpolation【460321113036012†L186-L194】.
  • Scope variables at the appropriate level to avoid unintended inheritance.
  • Use ITCSS to structure your stylesheets for scalability.
  • Beware of cascade order when combining layers, imports, and inline styles.

# Quick Cheatsheet

  • Custom Properties Syntax: --name: value; and var(--name, fallback).
  • @property: register custom properties with syntax, initial-value, inherits【460321113036012†L186-L194】.
  • Themes: override tokens under :root or containers.
  • Methodologies: BEM for naming; ITCSS for ordering; @layer for cascade control.
  • Scope: experimental @scope limits style bleed.

# Practice Tasks

  1. Define design tokens for a brand (colors, fonts, spacing) and apply them across a form component. Include light and dark themes.
  2. Register a custom property for rotation using @property and animate it on hover.
  3. Organize a small project using ITCSS layers and BEM naming conventions.
  4. Experiment with @scope by styling elements only within a specific container.

# Review Questions

  1. How do custom properties participate in the cascade and inheritance?
  2. What benefits does @property provide over unregistered custom properties【460321113036012†L186-L194】?
  3. Why might you choose a naming convention like BEM? Provide an example.
  4. Explain how ITCSS organizes stylesheets and the reasoning behind its inverted triangle.
  5. What problems do cascade layers help solve in large projects?