Skip to content

Conversation

@zehjotkah
Copy link
Contributor

@zehjotkah zehjotkah commented Feb 3, 2026

Problem

When defining CSS variables with different values for condition-based breakpoints (e.g., prefers-color-scheme:dark vs prefers-color-scheme:light), designers had no way to preview these variations without manually changing system preferences.

Example:

:root {
  --primary-color: #000;
  --background: #fff;
}

@media (prefers-color-scheme: dark) {
  :root {
    --primary-color: #fff;
    --background: #000;
  }
}

Previously, testing dark mode required switching OS settings back and forth.

Solution

Implements runtime CSS media rule manipulation to simulate condition-based breakpoints without changing system settings. When a designer selects a condition-based breakpoint, the simulator dynamically modifies CSS media rules:

  • Matching rules (e.g., prefers-color-scheme:dark when dark is selected) → replaced with (min-width: 0px) (always true)
  • Non-matching rules → appended with (max-width: 0px) (always false)
  • Original media queries are stored and restored when switching away

Features

Core Functionality:

  • Simulates media query conditions by replacing them with always-true/false queries
  • Supports all condition-based media features (prefers-color-scheme, prefers-reduced-motion, etc.)
  • Handles both spaced and non-spaced formats

Performance:

  • Caches media rules by feature to avoid repeated DOM traversal
  • Debounces rapid breakpoint changes (50ms)
  • Uses WeakMap for automatic memory management

Robustness:

  • Validates restoration success with warning logs
  • Handles CORS-restricted stylesheets gracefully
  • Proper cleanup on abort signal with cache clearing

Technical Implementation

Key Functions:

  • parseCondition() - Parses condition strings
  • getMediaRulesForFeature() - Caches and retrieves relevant media rules
  • applySimulation() - Debounced application of media rule modifications
  • restoreAllRules() - Restores original media queries
  • subscribeBreakpointSimulator() - Integrates with nano-states and lifecycle

Integration:

  • Subscribes to $selectedBreakpoint nano-state
  • Runs in design mode only
  • Cleanup via AbortSignal

Testing Instructions

Setup:

  1. Create CSS variables with condition-based values
  2. Configure breakpoints with conditions (e.g., prefers-color-scheme:light, prefers-color-scheme:dark)

Test Cases:

  • Select condition-based breakpoint → verify canvas reflects correct theme without changing OS settings
  • Rapidly switch between breakpoints → verify smooth transitions
  • Switch to width-based breakpoint → verify original media queries are restored
  • Check console for errors (should only see warnings for legitimate issues)

Files Changed

  • apps/builder/app/canvas/shared/breakpoint-simulator.ts - New feature (210 lines)
  • apps/builder/app/canvas/canvas.tsx - Integration

Impact

Designers can now preview dark/light themes and other condition-based styles instantly without changing system settings, significantly improving the workflow for building modern, accessible interfaces.

Implements runtime CSS media rule manipulation to simulate condition-based
breakpoints (e.g., prefers-color-scheme) without changing system settings.

Features:
- Simulates media query conditions by replacing them with always-true/false queries
- Caches media rules by feature to avoid repeated DOM traversal
- Debounces rapid breakpoint changes (50ms) for performance
- Validates restoration success with warning logs
- Proper cleanup on abort signal with cache clearing
- Handles CORS-restricted stylesheets gracefully

Technical implementation:
- Uses WeakMap for automatic memory management of original media texts
- Separates immediate and debounced application logic
- Integrates with nano-states for reactive breakpoint selection
- Supports both spaced and non-spaced media query formats

This enables designers to preview different breakpoint conditions in the
builder without modifying browser/system preferences.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant