parcel-bundler / lightningcss

An extremely fast CSS parser, transformer, bundler, and minifier written in Rust.
https://lightningcss.dev
Mozilla Public License 2.0
6.36k stars 182 forks source link

`light-dark` is broken when children have different `color-scheme`'s #821

Open foxt opened 1 week ago

foxt commented 1 week ago

If you take the following HTML

<p>This text should have a black background</p>

And apply the following CSS:

:root {
  --background: light-dark(white, black);
  --text: light-dark(black, white);
}

p {
  color: var(--text);
  background: var(--background);
  color-scheme: dark;
}

The text changes to white text on black background, as expected because color-scheme is set to dark.

However, change this to the transpiled CSS generated by lightningcss

:root{--background:var(--lightningcss-light,#fff)var(--lightningcss-dark,#000);--text:var(--lightningcss-light,#000)var(--lightningcss-dark,#fff)}p{color:var(--text);background:var(--background);--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}

And the text is black on white. I believe this is because the polyfill uses css variables which do not recompute if child elements change any of the input variables, where as light-dark seems to do. You currently need to re-apply the :root theme variables on every element that changes color-scheme

Hysterelius commented 4 days ago

I have a similar problem, when I use this rust code:

use lightningcss::{
    printer::PrinterOptions,
    stylesheet::{MinifyOptions, ParserOptions, StyleSheet},
    targets::Browsers,
};

const STYLESHEET: &str = r#"
html {
  color-scheme: light dark;
}

html[data-theme=light] {
  color-scheme: light;
}

html[data-theme=dark] {
  color-scheme: dark;
}

button {
  background: light-dark(#aaa, #444);
}

"#;

fn main() {
    let mut stylesheet = StyleSheet::parse(STYLESHEET, ParserOptions::default()).unwrap();

    let _ = stylesheet.minify(MinifyOptions::default());

    let result = stylesheet
        .to_css(PrinterOptions {
            targets: Browsers {
                chrome: Some(96 << 16),
                ..Browsers::default()
            }
            .into(),
            ..Default::default()
        })
        .unwrap();

    println!("{}", result.code);
}

(which is the same as the [docs](https://lightningcss.dev/transpilation.html#light-dark()-color-function))

It incorrectly transpiles into:

html {
  color-scheme: light dark;
}

html[data-theme="light"] {
  color-scheme: light;
}

html[data-theme="dark"] {
  color-scheme: dark;
}

button {
  background: var(--lightningcss-light, #aaa) var(--lightningcss-dark, #444);
}

Which is invalid css (and also doesn't match the docs' code), as it doesn't ever define the variables.