How to Use prefers-color-scheme in Standalone SVGs

Integrating the prefers-color-scheme media query directly into standalone SVG files allows icons, logos, and illustrations to dynamically switch between light and dark modes without requiring external CSS or JavaScript. This article covers how to embed internal styles, use CSS custom properties within SVG elements, and ensure your standalone SVGs respond correctly when loaded in web browsers or across different display contexts.

Embedding Media Queries in SVGs

SVGs support internal stylesheet declarations via the <style> tag placed inside the <defs> or directly inside the root <svg> element. Because standalone SVG assets operate in their own isolated document context, the media queries inside the SVG evaluate against the system preferences of the user’s operating system or browser.

Here is a basic structure for an SVG that changes its fill color based on the user’s system theme:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
  <style>
    .theme-shape {
      fill: #111827; /* Default: Light Mode */
    }

    @media (prefers-color-scheme: dark) {
      .theme-shape {
        fill: #f9fafb; /* Dark Mode */
      }
    }
  </style>
  <circle class="theme-shape" cx="50" cy="50" r="40" />
</svg>

Using CSS Custom Properties for Scalability

For complex illustrations containing multiple elements, managing colors using CSS variables (custom properties) keeps the code maintainable. You can assign default values at the :root level and override them inside the dark mode media query.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
  <style>
    :root {
      --bg-color: #ffffff;
      --primary-color: #2563eb;
      --text-color: #1f2937;
    }

    @media (prefers-color-scheme: dark) {
      :root {
        --bg-color: #1f2937;
        --primary-color: #60a5fa;
        --text-color: #f9fafb;
      }
    }

    .background { fill: var(--bg-color); }
    .accent { fill: var(--primary-color); }
    .label { fill: var(--text-color); font-family: sans-serif; font-size: 12px; }
  </style>

  <rect class="background" width="100" height="100" rx="10" />
  <circle class="accent" cx="50" cy="40" r="20" />
  <text class="label" x="50" y="80" text-anchor="middle">Theme</text>
</svg>

Methods for Displaying Theme-Aware SVGs

Standalone SVGs containing internal media queries respond differently depending on how they are embedded into an HTML document:

  1. Standard <img> tags: Modern browsers allow embedded SVGs inside standard <img src="icon.svg"> tags to evaluate prefers-color-scheme correctly.
  2. Direct Browser Navigation: Opening the SVG directly via its URL will trigger the media query according to browser and OS settings.
  3. <picture> and <source> Alternative: If you need separate assets rather than internal switching, the HTML <picture> element can serve different standalone files using media="(prefers-color-scheme: dark)".
  4. CSS Backgrounds: Using the SVG as a background-image: url('icon.svg') in CSS will also respect the internal color scheme queries in modern browser engines.

Technical Constraints and Best Practices