The CSS Custom Property Toggle Trick

Learn how to control multiple CSS properties with a single custom property using the space toggle hack, @property, and four proven techniques for conditional styling.

CSS custom properties (CSS variables) have revolutionized how we approach styling on the web. But beyond simple value storage, there's a powerful technique that allows you to toggle multiple property values with a single custom property--a technique so clever it was independently discovered by multiple developers before being named the "space toggle hack." This guide explores how you can use a single custom property to conditionally apply entire sets of styles across your codebase, enabling elegant theme switching, component variations, and responsive behavior without JavaScript.

Mastering these CSS techniques is essential for modern web development and building maintainable styling systems that scale efficiently across large applications.

What Are CSS Custom Properties

CSS custom properties are entities defined by CSS authors that contain specific values to be reused throughout a document. Unlike preprocessor variables, custom properties are true CSS properties--they cascade, inherit, and can be changed at runtime with JavaScript.

Key Characteristics

  • Cascade inheritance: Child elements inherit custom properties from parents, enabling scoped theming
  • Runtime modification: JavaScript can update custom properties instantly without re-rendering
  • Fallback values: The var() function accepts a second parameter as fallback when the property is undefined
  • Media query integration: Custom properties can respond to viewport changes naturally

Understanding custom properties is foundational for advanced CSS techniques. For a deeper dive into CSS units and responsive sizing, explore our guide on rem vs em units and how they relate to custom property scoping.

The Fallback Mechanism

The var() function accepts two parameters: the custom property name and an optional fallback value. When the custom property is not defined or set to certain values, the fallback is used instead. This fallback mechanism is the key to the toggle trick.

var() Fallback Syntax
1/* Basic fallback syntax */2color: var(--my-color, #000000);3 4/* Fallback can be another custom property */5background: var(--primary-color, var(--default-color, #fff));

The Space Toggle Hack

The space toggle hack leverages two special values that work universally in var() calls:

  1. The space value (--var: ;): Creates a literal single-space value that doesn't affect any CSS property
  2. The initial value (--var: initial): Makes the property use its initial value, effectively triggering fallbacks

How the Space Toggle Works

/* Without toggle - base styles */
button {
 background: linear-gradient(white, transparent) hsl(220 10% 50%);
 border: 1px solid rgb(0 0 0 / .1);
 color: rgb(0 0 0 / .8);
}

/* With space toggle - append styles when toggle is ON */
button {
 --is-raised: ; /* Space = OFF, initial = ON */
 background: var(--is-raised, linear-gradient(white, transparent)) hsl(220 10% 50%);
 border: 1px solid var(--is-raised, rgb(0 0 0 / .1));
 color: rgb(0 0 0 / var(--is-raised, .8));
}

When --is-raised is set to initial, the fallback values (gradient, border color, opacity) are applied. When set to a space, and base styles remain the fallback is ignored.

Practical Example: Button State Toggle

:root {
 --ON: initial;
 --OFF: ;
}

button.flat {
 --is-raised: var(--OFF);
}

button.raised {
 --is-raised: var(--ON);
 background: var(--is-raised, linear-gradient(hsl(0,0%,97%), hsl(0,0%,92%))) hsl(220 10% 50%);
 border: 1px solid var(--is-raised, rgb(0 0 0 / .1));
 box-shadow: var(--is-raised, inset 0 1px 0 hsl(0,0%,100%), 0 1px 3px rgba(0,0,0,.2));
 text-shadow: var(--is-raised, 0 1px 0 hsl(0,0%,100%));
}

The toggle controls:

  • Background gradient
  • Subtle border
  • Box shadow for depth
  • Text shadow for engraved look

Four Techniques for CSS Property Toggling

1. The calc() Method

Uses calc() to multiply values by 0 or 1, enabling or disabling styles:

--icon-visible: 1;

.icon {
 width: calc(16px * var(--icon-visible, 1));
}

button {
 gap: calc(1ch * var(--icon-visible, 1) * var(--label-visible, 1));
 background: color-mix(in srgb, #d44, #0000 calc(100% * var(--invert, 0)));
}

Pros: Best browser support, works with transforms and color-mix Cons: Only works with numeric values

2. Container Style Queries

Container style queries allow conditional styling based on custom property values:

@container style(--icon-visible: no) {
 .icon {
 display: none;
 }
}

@container style(--label-visible: no) {
 .label {
 position: absolute;
 clip: rect(0 0 0 0);
 }
}

Pros: More intuitive, can toggle non-numeric properties Cons: Limited browser support (Chromium only)

3. @property Value Coalescing

Defining properties with multiple valid syntaxes:

@property --label-visible {
 syntax: 'yes | no';
 inherits: true;
 initial-value: yes;
}

Pros: Type-safe definitions, no runtime calculations Cons: Requires many property definitions, verbose code

4. Animation @keyframes Method

Using animation state to toggle styles:

@keyframes label-visibility {
 from {
 position: absolute;
 clip: rect(0, 0, 0, 0);
 }
}

.label {
 animation: label-visibility 1s calc(var(--label-visible, 1) * -1s)
 steps(2) paused forwards;
}

Pros: Works in all browsers Cons: Complex to understand, animation overhead

Practical Use Cases

Theme Switching

A single property can toggle multiple theme values:

body {
 background: var(--theme-bg);
 color: var(--theme-text);
}

.highlighted {
 --apply-dark-theme: initial;
 background: var(--apply-dark-theme, var(--theme-bg));
 color: var(--apply-dark-theme, var(--theme-text));
}

Responsive Component Variations

Toggles work with media queries for responsive behavior:

ui-button {
 --icon-visible: yes;
 --label-visible: yes;
}

@media (max-width: 35em) {
 ui-button {
 --label-visible: no; /* Hide labels on mobile */
 }
}

Interactive States

Hover and focus states with toggles:

button {
 --interactive: ;
 transition: all 0.2s ease;
}

button:hover {
 --interactive: initial;
 transform: translateY(-2px);
 box-shadow: var(--interactive, 0 4px 12px rgba(0,0,0,.15));
}

Best Practices

Use Named Constants

Semantic naming improves code readability:

:root {
 /* Semantic toggle states */
 --ON: initial;
 --OFF: ;
 
 /* Theme modes */
 --DARK_MODE: initial;
 --LIGHT_MODE: ;
}

Document Toggle Properties

Add comments for maintainability:

/**
 * Toggle for raised button appearance
 * @type {initial | empty}
 * @usage Set to 'initial' for raised effect, empty for flat
 */
--is-raised: ;

Performance Optimization

  • Toggle visual-only properties (transform, opacity) rather than layout properties
  • Use will-change for animated properties
  • Avoid toggling display or position when possible
  • Hardware-accelerated properties (transform, opacity) are more performant

For comprehensive CSS performance optimization, consider partnering with our web development team to implement these best practices across your codebase.

Browser Support

Custom Properties (var())

BrowserVersionSupport
Chrome49+Full
Firefox31+Full
Safari9.1+Full
Edge15+Full

@property At-Rule

BrowserVersionSupport
Chrome73+Full
Firefox97+Full
Safari16.4+Full
Edge73+Full

Container Style Queries

BrowserVersionSupport
Chrome105+Full
Edge105+Full
Firefox110+Behind flag
SafariNot yetNone

Fallback Strategy

/* Base styles - works everywhere */
button {
 /* Essential styles */
}

/* Toggle enhancements - @property with fallback */
@supports (--custom-property: initial) {
 button {
 /* Toggle-enhanced styles */
 }
}

Limitations and Future of CSS Conditionals

Current Limitations

  1. No true if/else: The toggle hack only works for appending values or using fallbacks
  2. Cannot swap values entirely: Cannot say "red if X, white otherwise"
  3. Readability concerns: --var: ; looks like a mistake
  4. Property limitations: Some properties cannot be toggled this way

Upcoming Features

  • CSS if() function: In discussions at W3C
  • container style() queries: Gaining browser support
  • CSS @when: Proposal for conditional CSS rules

Conclusion

The CSS custom property toggle trick opens up new possibilities for conditional styling without JavaScript. Whether you use the space toggle hack for maximum compatibility, the initial value for semantic clarity, or @property for type-safe definitions, this technique enables elegant theming systems, responsive components, and interactive states.

Start with:

  • Space toggle for maximum compatibility
  • @property for larger projects
  • Container style queries as browser support improves

Ready to level up your CSS skills? Our web development services team can help you implement advanced CSS patterns like these to build maintainable, performant websites.

Ready to Build Modern Web Applications?

Our team specializes in performance-first web development using Next.js and modern CSS techniques.