Logical Operations with CSS Variables

Master NOT, AND, OR, XOR and more using calc() to build adaptive, themeable interfaces

CSS custom properties (variables) have revolutionized how we approach styling on the web. While CSS doesn't provide built-in logical functions like not() or and(), we can emulate these operations using arithmetic calculations within the calc() function. This opens up powerful possibilities for creating adaptive, themeable interfaces that respond to multiple conditions simultaneously.

The ability to combine switch variables with logical operations separates intermediate CSS practitioners from advanced developers who can build truly dynamic styling systems.

Understanding Switch Variables

Before diving into logical operations, we need to understand the concept of a switch variable--a CSS custom property that holds either 0 or 1. This binary state forms the foundation for all logical operations we'll explore.

Defining Switch Variables

Switch variables are defined as any other CSS custom property, but their values are constrained to 0 (false/off) or 1 (true/on):

:root {
 --wide-screen: 1;
 --dark-mode: 0;
 --sidebar-enabled: 1;
}

These variables can be toggled through various means:

  • CSS custom property cascades
  • Media queries
  • Container queries
  • State pseudo-classes like :checked

For deeper exploration of CSS variable fundamentals, see our guide on CSS viewport units which demonstrates how variables integrate with responsive design patterns.

The Core Logical Operations

CSS provides no built-in logical functions, but we can achieve all fundamental operations using arithmetic in calc(). Each operation serves a specific purpose in building conditional styles.

CSS Logical Operations Formulas
OperationFormulaReturns 1 when
NOTcalc(1 - var(--switch))Switch is 0
ANDcalc(var(--a) * var(--b))Both A and B are 1
NANDcalc(1 - var(--a) * var(--b))NOT both are 1
ORcalc(1 - (1 - var(--a)) * (1 - var(--b)))At least one is 1
NORcalc((1 - var(--a)) * (1 - var(--b)))Both are 0
XORcalc((var(--a) - var(--b)) * (var(--a) - var(--b)))A and B differ

The NOT Operation

The NOT operation inverts a switch variable's value. If the input is 1, the output is 0, and vice versa.

Formula

--not-switch: calc(1 - var(--switch));

How It Works

InputOutput
--switch: 0--not-switch: 1 - 0 = 1
--switch: 1--not-switch: 1 - 1 = 0

Use Cases

The NOT operation is essential for creating complementary states, such as toggling between light and dark themes without duplicating stylesheets, or creating disabled states that are the inverse of enabled states.

The AND Operation

The AND operation returns 1 only if both operands are 1. If either operand is 0, the result is 0.

Formula

--and-result: calc(var(--switch-a) * var(--switch-b));

Why Multiplication?

Multiplying by 0 always produces 0, making multiplication the perfect operation for AND:

ABA × B
000
010
100
111

Use Cases

AND operations excel at creating compound conditions where multiple states must all be true. For example, enabling an advanced panel only when both the wide-screen breakpoint is active AND the user has explicitly enabled advanced controls.

The OR Operation

The OR operation returns 1 if at least one operand is 1. Only when both operands are 0 does the result become 0.

Formula

--or-result: calc(1 - (1 - var(--switch-a)) * (1 - var(--switch-b)));

Why Not Simple Addition?

At first glance, addition seems natural, but 1 + 1 = 2 which breaks our binary system. The solution leverages De Morgan's law: NOT (A OR B) = (NOT A) AND (NOT B).

Use Cases

OR operations are ideal for fallback scenarios--for instance, showing a sidebar if EITHER the user explicitly enabled it OR we're on a wide screen.

The XOR Operation

XOR (exclusive OR) returns 1 when the operands are different, and 0 when they are the same.

Formula

--xor-result: calc((var(--switch-a) - var(--switch-b)) * (var(--switch-a) - var(--switch-b)));

How It Works

  1. Subtraction gives us the difference: 0-0=0, 0-1=-1, 1-0=1, 1-1=0
  2. Squaring (multiplying by itself) converts -1 and 1 to 1, while 0 stays 0

Use Cases

XOR is perfect for toggle states where you want the opposite behavior when two conditions differ--for example, alternating between two layouts when exactly one of two conditions is active.

Practical Example: Responsive Control Panel

Let's apply these concepts to a real-world scenario. We want an advanced control panel that should:

  • Be hidden on narrow screens when disabled
  • Be visible on wide screens regardless of enabled state
  • Be visible when enabled, regardless of screen width

The CSS Implementation

body {
 --wide: var(--wide-screen, 0);
}

.advanced-panel {
 --enabled: var(--controls-enabled, 0);
 --or: calc(1 - (1 - var(--wide)) * (1 - var(--enabled)));
 
 margin: calc(var(--or) * 1rem) 0;
 height: calc(var(--or) * 200px);
 filter: opacity(calc(1 - var(--enabled) * 0.3));
}

By computing an OR value, we determine whether to show the panel. When either --wide or --enabled is 1, the panel becomes visible with full dimensions.

Performance Considerations

calc() Overhead

Each calc() computation adds slight processing overhead. For simple toggles, the impact is negligible. However, deeply nested calculations or animating values derived from logical operations can affect rendering performance.

Optimization Strategies

  • Cache intermediate results: Store computed values in custom properties to avoid recalculation
  • Use CSS containment: Apply contain: layout paint for complex components
  • Prefer transforms and opacity: These animate efficiently when derived from logical operations
  • Test on target devices: Especially important for lower-powered mobile devices

Browser Compatibility

Modern browsers handle CSS variable calculations reliably. When supporting older browsers:

  • Test thoroughly across target browsers
  • Provide fallbacks using the cascade
  • Use feature detection (@supports) for critical functionality

Optimized CSS performance also contributes to better SEO performance, as page speed and rendering efficiency are key ranking factors for search engines.

Best Practices

Naming Conventions

Use clear, descriptive names for switch variables:

  • --is-enabled, --is-active for binary states
  • --feature-visible, --mode-dark for feature flags
  • --component-primary, --orientation-vertical for component types

Organization

Group related logical operations for maintainability:

/* Logical operations - grouped together */
--not-enabled: calc(1 - var(--is-enabled));
--all-true: calc(var(--a) * var(--b) * var(--c));
--any-true: calc(1 - (1 - var(--a)) * (1 - var(--b)));

Debugging

When logical operations don't behave as expected:

  1. Log computed values using color: rgb(var(--result), 0, 0)
  2. Test each operation in isolation
  3. Verify switch variable values in browser dev tools

Conclusion

Logical operations with CSS variables transform custom properties from simple value storage into a powerful conditional system. By mastering NOT, AND, NAND, OR, NOR, and XOR operations using calc(), you can build adaptive interfaces that respond elegantly to multiple conditions without JavaScript.

This approach keeps stylesheets DRY, maintainable, and expressive--demonstrating the full potential of modern CSS. As CSS continues evolving with new capabilities like native conditionals, these foundational techniques will remain valuable for building sophisticated, maintainable styling systems for your web development projects.

CSS-Tricks' comprehensive guide on logical operations with CSS variables provides detailed formulas and additional techniques for advanced practitioners.

Frequently Asked Questions

Ready to Modernize Your CSS Architecture?

Our team of CSS experts can help you implement advanced styling techniques, optimize performance, and build maintainable design systems for your web applications.

Sources

  1. CSS-Tricks: Logical Operations with CSS Variables - Comprehensive guide covering all logical operations with detailed formulas
  2. MDN: Using CSS custom properties (variables) - Official documentation on CSS variable fundamentals