User Preference Media Queries

What You'll Learn

  • Detect and respond to system-level user preferences with CSS media queries
  • Implement automatic dark mode with prefers-color-scheme
  • Respect motion preferences using prefers-reduced-motion for accessibility
  • Adapt to contrast preferences with prefers-contrast
  • Handle transparency preferences with prefers-reduced-transparency
  • Create accessible, user-respecting designs that honor system settings
  • Combine preference queries with custom properties for maintainable themes

Introduction to Preference Queries

Modern CSS allows you to detect and respond to user system preferences automatically. These preference media queries enable your designs to respect accessibility settings, visual preferences, and motion sensitivities that users have configured at the operating system level. This creates more inclusive and comfortable experiences without requiring manual user configuration on your site.

Preference queries are essential for accessibility. Users with vestibular disorders may have enabled reduced motion settings. Users with light sensitivity may prefer dark themes. By respecting these preferences automatically, you demonstrate commitment to inclusive design and provide better experiences for users with diverse needs.

prefers-color-scheme - Dark Mode

The prefers-color-scheme media query detects whether a user has requested a light or dark color theme through their operating system settings. This is the foundation for implementing automatic dark mode support in your designs.

/* Default light mode colors */ :root { --bg-primary: #ffffff; --bg-secondary: #f3f4f6; --text-primary: #111827; --text-secondary: #6b7280; --accent: #3b82f6; } /* Dark mode colors */ @media (prefers-color-scheme: dark) { :root { --bg-primary: #1f2937; --bg-secondary: #374151; --text-primary: #f9fafb; --text-secondary: #d1d5db; --accent: #60a5fa; } } /* Apply colors using custom properties */ body { background-color: var(--bg-primary); color: var(--text-primary); }

Complete Dark Mode Implementation

/* Light mode (default) */ :root { --bg-primary: #ffffff; --bg-secondary: #f5f5f5; --bg-tertiary: #e5e7eb; --text-primary: #111827; --text-secondary: #6b7280; --text-tertiary: #9ca3af; --border-color: #d1d5db; --accent-color: #3b82f6; --accent-hover: #2563eb; --success: #10b981; --warning: #f59e0b; --error: #ef4444; } /* Dark mode */ @media (prefers-color-scheme: dark) { :root { --bg-primary: #111827; --bg-secondary: #1f2937; --bg-tertiary: #374151; --text-primary: #f9fafb; --text-secondary: #d1d5db; --text-tertiary: #9ca3af; --border-color: #4b5563; --accent-color: #60a5fa; --accent-hover: #3b82f6; --success: #34d399; --warning: #fbbf24; --error: #f87171; } /* Adjust images for dark mode */ img { opacity: 0.9; } /* Adjust shadows for dark mode */ .card { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.4); } }

prefers-reduced-motion - Accessibility

The prefers-reduced-motion media query detects if a user has requested to minimize the amount of animation or motion. This is critical for users with vestibular disorders, epilepsy, or those who simply find animations distracting or nauseating. Respecting this preference is not optional - it's an accessibility requirement.

/* Animations by default */ .element { animation: bounce 2s infinite; transition: all 0.3s ease; } /* Respect reduced motion preference */ @media (prefers-reduced-motion: reduce) { .element { animation: none; } /* Allow only essential transitions with minimal duration */ * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } }

Safe Animation Patterns

/* Provide alternative feedback without motion */ .button { background: blue; transform: scale(1); transition: transform 0.3s, background 0.2s; } .button:hover { background: darkblue; transform: scale(1.05); } @media (prefers-reduced-motion: reduce) { .button { transition: background 0.2s; /* Keep only color transition */ } .button:hover { transform: none; /* Remove scale animation */ background: darkblue; /* Keep color change for feedback */ } }

prefers-contrast - High Contrast Mode

The prefers-contrast media query detects if a user has requested higher or lower contrast. High contrast mode helps users with low vision or color blindness distinguish interface elements more easily.

/* Normal contrast (default) */ .card { border: 1px solid #e5e7eb; background: #f9fafb; } /* High contrast mode */ @media (prefers-contrast: high) { .card { border: 3px solid #000000; background: #ffffff; } /* Stronger text contrast */ body { color: #000000; } /* Bolder fonts */ h1, h2, h3 { font-weight: bold; } /* Remove subtle effects */ .subtle-shadow { box-shadow: none; border: 2px solid #000000; } } /* Low contrast mode */ @media (prefers-contrast: low) { .card { border: 1px solid #d1d5db; opacity: 0.9; } }

prefers-reduced-transparency

The prefers-reduced-transparency media query detects if a user has requested to reduce transparent or translucent effects. This can help users with visual processing issues or those who find transparency effects distracting.

/* Glass-morphism effect (default) */ .modal { background: rgba(255, 255, 255, 0.8); backdrop-filter: blur(10px); } /* Solid background for clarity */ @media (prefers-reduced-transparency: reduce) { .modal { background: #ffffff; backdrop-filter: none; } /* Remove all transparency */ .overlay { background: #000000; opacity: 1; } }

Combining Multiple Preferences

Users may have multiple preferences enabled simultaneously. Your CSS should handle these combinations gracefully to provide the best possible experience.

/* Dark mode with reduced motion */ @media (prefers-color-scheme: dark) and (prefers-reduced-motion: reduce) { .element { background: var(--bg-dark); animation: none; transition: none; } } /* High contrast with reduced transparency */ @media (prefers-contrast: high) and (prefers-reduced-transparency: reduce) { .card { background: #ffffff; border: 3px solid #000000; backdrop-filter: none; } } /* Dark mode with high contrast */ @media (prefers-color-scheme: dark) and (prefers-contrast: high) { :root { --bg-primary: #000000; --text-primary: #ffffff; --border-color: #ffffff; } }

JavaScript Detection

While CSS handles styling automatically, you may need JavaScript to detect preferences for application logic or to provide manual override controls.

// Detect color scheme const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; // Listen for changes window.matchMedia('(prefers-color-scheme: dark)') .addEventListener('change', (e) => { const newScheme = e.matches ? 'dark' : 'light'; console.log('Color scheme changed to:', newScheme); // Update UI or application state }); // Detect reduced motion const prefersReducedMotion = window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches; if (prefersReducedMotion) { // Disable animations in your app disableAnimations(); } // Detect high contrast const prefersHighContrast = window.matchMedia( '(prefers-contrast: high)' ).matches; // Detect reduced transparency const prefersReducedTransparency = window.matchMedia( '(prefers-reduced-transparency: reduce)' ).matches;

Testing User Preferences

Testing these preferences during development is essential. Here's how to test on different platforms and in browsers.

Operating System Settings

/* macOS: - Dark Mode: System Preferences → General → Appearance - Reduce Motion: System Preferences → Accessibility → Display → Reduce motion - Contrast: System Preferences → Accessibility → Display → Increase contrast Windows: - Dark Mode: Settings → Personalization → Colors → Choose your color - Reduce Motion: Settings → Ease of Access → Display → Show animations - Contrast: Settings → Ease of Access → High contrast Linux (varies by distribution): - Usually in System Settings → Appearance */

Browser DevTools

/* Chrome/Edge: 1. Open DevTools (F12) 2. Cmd/Ctrl + Shift + P → "Emulate CSS prefers-color-scheme" 3. Or: DevTools → Rendering tab → Emulate CSS media feature Firefox: 1. Open DevTools (F12) 2. Inspector → Rules panel → Toggle color scheme icon 3. Or about:config → ui.systemUsesDarkTheme (0=light, 1=dark) Safari: 1. Develop menu → Experimental Features → Dark Mode CSS Support 2. Elements tab → Styles panel → Force color scheme */

Key Takeaways