Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

postcss-color-scheme

Package Overview
Dependencies
Maintainers
0
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

postcss-color-scheme

postcss plugin for handling prefers-color-scheme more gracefully

  • 2.1.0
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
0
Created
Source

postcss-color-scheme

github.actions.changesets.badge codecov.badge MIT npm.badge

Postcss plugin for handling prefers-color-scheme, plus Tailwind V4 variants (optional).

Input

.my-class {
	color: black;

	@color-scheme dark {
		color: white;
	}
}

Output

.my-class {
	color: black;

	html[data-color-scheme='dark'] & {
		color: white;
	}

	@media (prefers-color-scheme: dark) {
		html:not([data-color-scheme='light']) & {
			color: white;
		}
	}
}

[!NOTE] Notice postcss-color-scheme preserves CSS nesting as it has landed in all major browsers as of this writing. If you need to target older browsers, consider adding additional transform with postcss-nesting (not postcss-nested).

Changelog

Installation

npm install --save-dev postcss postcss-color-scheme
yarn add -D postcss postcss-color-scheme
pnpm add -D postcss postcss-color-scheme

Add to your postcss config

/* @file: postcss.config.js */
import postcssColorScheme from 'postcss-color-scheme';

export default {
	plugins: [postcssColorScheme()],
};

Design Decisions

You might have noticed a couple of opinionated code at the top of this document. These are extracted from my daily work, and currently serve my use cases very well. Should you have concerns, suggestions for improvements, or solution for making this more generic, feel free to open an issue. Thanks!

  1. Rely on data-color-scheme for explicit theme settings. This requires setting data-color-scheme on the html element.

  2. Provide fallback when user has not explicitly select a theme. Let's refer to the demo above, with rules enumerated:

    /* (1) */
    .my-class {
    	color: black;
    }
    
    /* (2) */
    html[data-color-scheme='dark'] .my-class {
    	color: white;
    }
    
    /* (3) */
    @media (prefers-color-scheme: dark) {
    	html:not([data-color-scheme='light']) .my-class {
    		color: white;
    	}
    }
    

    Imagine your system provides 3 options: dark, light, and system (default, auto, i.e respect system preferences). There are 4 possible scenarios.

    1. User has not explicitly selected a theme (theme = system), and the system prefers light (prefers-color-scheme = light):

      --> (1) applies.

    2. User has not explicitly selected a theme (theme = system), and the system prefers dark (prefers-color-scheme = dark):

      --> (1) & (3) applies, (3) takes precedence because of its higher specificity.
      
    3. User selected dark (data-color-theme set to dark on html) :

      --> (1) & (2) applies, (2) takes precedence because of its higher specificity.

    4. User selected light (data-color-theme set to light on html) :

      --> (1) applies.

    flowchart TD
        A[Has user explicitly selected theme?] -->|Yes| B[Which mode?]
        B --> Light
        B --> Dark
        A -->|No| C[prefers-color-scheme?]
        C -->Light
        C -->Dark
    

What about the light-dark() Function?

As of this writing, the light-dark() CSS function already has pretty good support across browsers, and is a valid solution to handle light-dark mode. However, colors declared with light-dark are not as flexible. Consider the following setup:

:root {
	--regular-color: green;
	--light-dark-color: light-dark(red, blue);
}

We can use utilize the relatively new relative color syntax with --regular-color...

.regular {
	/* turn from green to redish while keeping perceived lightness and chroma */
	color: oklch(from var(--regular-color) l c calc(h - 120));
}

...while it is not possible today with light-dark:

.light-dark {
	 /* invalid and ignored by browser */
	color: oklch(from var(--light-dark-color) l c calc(h - 120));
}

Although color-mix does seem to work. Overall, until browser has better support for light-dark, postcss-color-scheme provides a more universal solution.

The color-scheme At-Rule

This plugin essentially provides a new at-rule, @color-scheme; it requires a parameter with value of either dark or light.

:root {
	@color-scheme light {
		color: black;
	}

	@color-scheme dark {
		color: white;
	}
}

Usage in Svelte Style Tag

Styling in Svelte is component-scoped by default. From Svelte 5, you can wrap the @color-scheme at-rule in a :global block. For example:

<main></main>

<style lang="postcss">
	:global {
		main {
			@color-scheme dark {
				color: white;
			}
		}
	}
</style>

Tailwind Support

From Tailwind V4, simply add the following to your CSS:

/* app.css, or any Tailwind-aware context */
@import 'tailwindcss';
@import 'postcss-color-scheme/tailwind.css';

This exposes the light: and dark: variants for usage in markup. For example:

<input class="text-white dark:text-black light:border-gray-500" />

Note that these variants and the @color-scheme at-rule are complementary and not exclusive. Feel free to use both: the former is for markup, while the latter is for CSS.

[!NOTE] For Tailwind V3 and below, please use postcss-color-scheme v1.

Keywords

FAQs

Package last updated on 28 Nov 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc