CSS Custom Properties 2026
CSS Custom Properties 2026

CSS Custom Properties 2026: @property Goes Mainstream

CSS Custom Properties: @property Is Now Universal

CSS custom properties (--variable) have been around since 2017, but @property - which adds types, defaults, and animation - was experimental until recently. In 2026, it’s universally supported and changes how we build design systems.

Browser Support (2026)

BrowserSupportNotes
Chrome 85+FullSince Aug 2020
Edge 85+FullChromium-based
Firefox 128+FullSince July 2024
Safari 15.4+FullSince March 2022

Global support: ~95%

No more polyfills or fallbacks needed for most audiences.

The @property Game Changer

Before: Untyped Variables

:root {
  --primary-color: #3b82f6;
  --spacing: 16px;
  --opacity: 0.8;
}

/* Problems:
   1. Can't animate custom properties
   2. No type checking - any value accepted
   3. No fallback for inheritance issues
*/

After: Typed Variables with @property

@property --primary-color {
  syntax: '<color>';
  inherits: true;
  initial-value: #3b82f6;
}

@property --spacing {
  syntax: '<length>';
  inherits: true;
  initial-value: 16px;
}

@property --opacity {
  syntax: '<number>';
  inherits: false;
  initial-value: 0.8;
}

The Three Powers of @property

1. Type Safety with syntax

Define what values are valid:

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

@property --percentage {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

@property --size {
  syntax: '<length> | <percentage>';
  inherits: true;
  initial-value: 100%;
}

/* Invalid values are ignored */
.element {
  --angle: red; /* Ignored - not an angle */
  --angle: 45deg; /* Works */
}

Available syntax types:

2. Animation Support

Before @property, custom properties couldn’t animate:

/* WITHOUT @property - jumps instantly */
.card {
  --bg-color: blue;
  background: var(--bg-color);
  transition: --bg-color 0.3s; /* Doesn't work */
}

.card:hover {
  --bg-color: red; /* Instant change, no transition */
}

With @property:

@property --bg-color {
  syntax: '<color>';
  inherits: false;
  initial-value: blue;
}

.card {
  background: var(--bg-color);
  transition: --bg-color 0.3s ease;
}

.card:hover {
  --bg-color: red; /* Smooth color transition! */
}

3. Inheritance Control

Control whether values cascade down:

@property --theme-color {
  syntax: '<color>';
  inherits: true; /* Children inherit this */
  initial-value: #3b82f6;
}

@property --local-spacing {
  syntax: '<length>';
  inherits: false; /* Each element uses initial-value */
  initial-value: 1rem;
}

Real-World Patterns

Pattern 1: Animated Gradients

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

.animated-gradient {
  background: linear-gradient(
    var(--gradient-angle),
    #3b82f6,
    #8b5cf6
  );
  animation: rotate-gradient 3s linear infinite;
}

@keyframes rotate-gradient {
  to {
    --gradient-angle: 360deg;
  }
}

Pattern 2: Progress Indicators

@property --progress {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

.progress-bar {
  background: linear-gradient(
    90deg,
    #22c55e var(--progress),
    #e5e7eb var(--progress)
  );
  transition: --progress 0.5s ease-out;
}

.progress-bar[data-value="25"] { --progress: 25%; }
.progress-bar[data-value="50"] { --progress: 50%; }
.progress-bar[data-value="75"] { --progress: 75%; }
.progress-bar[data-value="100"] { --progress: 100%; }

Pattern 3: Theme System

@property --color-primary {
  syntax: '<color>';
  inherits: true;
  initial-value: #3b82f6;
}

@property --color-secondary {
  syntax: '<color>';
  inherits: true;
  initial-value: #64748b;
}

@property --radius {
  syntax: '<length>';
  inherits: true;
  initial-value: 0.5rem;
}

/* Theme variations */
.theme-rounded {
  --radius: 1rem;
}

.theme-sharp {
  --radius: 0;
}

.theme-warm {
  --color-primary: #f59e0b;
  --color-secondary: #92400e;
}

Pattern 4: Responsive Spacing Scale

@property --space-unit {
  syntax: '<length>';
  inherits: true;
  initial-value: 4px;
}

:root {
  --space-1: calc(var(--space-unit) * 1);  /* 4px */
  --space-2: calc(var(--space-unit) * 2);  /* 8px */
  --space-4: calc(var(--space-unit) * 4);  /* 16px */
  --space-8: calc(var(--space-unit) * 8);  /* 32px */
}

@media (min-width: 768px) {
  :root {
    --space-unit: 5px; /* Entire scale adjusts */
  }
}

Combining with Container Queries

@property --card-padding {
  syntax: '<length>';
  inherits: false;
  initial-value: 1rem;
}

.card-container {
  container: card / inline-size;
}

.card {
  padding: var(--card-padding);
  transition: --card-padding 0.2s ease;
}

@container card (width > 400px) {
  .card {
    --card-padding: 2rem;
  }
}

Fallback Strategies

For the ~5% without @property:

/* Define @property for supporting browsers */
@property --accent {
  syntax: '<color>';
  inherits: true;
  initial-value: #3b82f6;
}

/* Fallback works everywhere */
.element {
  --accent: #3b82f6;
  background: var(--accent);

  /* Animation only works with @property support */
  transition: --accent 0.3s;
}

Common Mistakes

Mistake 1: Forgetting initial-value

/* ❌ Missing initial-value */
@property --spacing {
  syntax: '<length>';
  inherits: true;
}

/* âś… Always provide initial-value */
@property --spacing {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}

Mistake 2: Wrong Syntax Type

/* ❌ Trying to use calc result as <integer> */
@property --columns {
  syntax: '<integer>';
  inherits: false;
  initial-value: 3;
}

.grid {
  --columns: calc(var(--base) / 2); /* Won't work - calc returns number */
}

/* âś… Use <number> for calculated values */
@property --columns {
  syntax: '<number>';
  inherits: false;
  initial-value: 3;
}

Key Takeaways

  1. Universal support - @property works in 95%+ of browsers
  2. Type safety - syntax validates values at the CSS level
  3. Animatable - Custom properties can now transition smoothly
  4. Inheritance control - Choose whether values cascade
  5. Design systems - Build more robust, predictable theming

@property transforms CSS custom properties from simple text substitution into a proper type system. In 2026, there’s no reason not to use it for any non-trivial design system.

Link copied!

Comments for csscst