Description
When a utility class combines a color-mode variant with a breakpoint variant (e.g. bg:black@dark@sm) and modeTrigger is media, the engine emits a malformed media query — the two media features are joined by a space instead of and:
@media (width>=52.125rem) (prefers-color-scheme:dark){.bg\:black\@dark\@sm{background-color:oklch(0% 0 none)}}
This is invalid CSS, so browsers drop the whole rule (the style silently never applies), and downstream CSS minifiers complain — e.g. esbuild during a Vite build:
▲ [WARNING] Expected "{" but found "(" [css-syntax-error]
The cause appears to be in packages/engine/src/utils/generate-condition.ts: when the mode's prefers-color-scheme component is pushed into an existing conditions.media array, generateCondition joins the media feature nodes with ' ' and no and combinator is inserted.
Note that @master/css-validator (same version) returns false for bg:black@dark@sm, so stacked variants may no longer be intended syntax in 2.0 — but then the expected behavior would be for the engine to reject the class rather than emit invalid CSS. Either outcome (emit ... and (prefers-color-scheme:dark), or treat the class as invalid) would be fine; silently generating a rule that browsers discard is the worst of both.
Expected: @media (width>=52.125rem) and (prefers-color-scheme:dark){...} — or the class is rejected as invalid.
Reproduction
bun add @master/css@rc @master/css-compiler@rc @master/css-engine@rc (all resolve to 2.0.0-rc.88)
master.css:
repro.mjs:
import { compileCSSManifestFile } from '@master/css-compiler'
import { MasterCSS } from '@master/css-engine'
const { manifest } = await compileCSSManifestFile('./master.css')
const css = new MasterCSS(manifest)
for (const name of ['bg:black@sm', 'bg:black@dark', 'bg:black@dark@sm']) {
console.log(name, '=>', css.generate(name).map(r => r.text).join(''))
}
bun repro.mjs prints:
bg:black@sm => @media (width>=52.125rem){.bg\:black\@sm{background-color:oklch(0% 0 none)}}
bg:black@dark => @media (prefers-color-scheme:dark){.bg\:black\@dark{background-color:oklch(0% 0 none)}}
bg:black@dark@sm => @media (width>=52.125rem) (prefers-color-scheme:dark){.bg\:black\@dark\@sm{background-color:oklch(0% 0 none)}}
The single-variant classes are correct; the stacked one is missing and between the two media features. The same output is produced through @master/css.vite in a real build.
System Informations
OS: macOS (arm64)
Node.js / runtime: Bun 1.3.0
Package Manager: bun
@master/css: 2.0.0-rc.88 (also present in earlier 2.0 rc versions; source on the `rc` branch still joins media condition nodes with a space)
Description
When a utility class combines a color-mode variant with a breakpoint variant (e.g.
bg:black@dark@sm) andmodeTriggerismedia, the engine emits a malformed media query — the two media features are joined by a space instead ofand:This is invalid CSS, so browsers drop the whole rule (the style silently never applies), and downstream CSS minifiers complain — e.g. esbuild during a Vite build:
The cause appears to be in
packages/engine/src/utils/generate-condition.ts: when the mode'sprefers-color-schemecomponent is pushed into an existingconditions.mediaarray,generateConditionjoins the media feature nodes with' 'and noandcombinator is inserted.Note that
@master/css-validator(same version) returnsfalseforbg:black@dark@sm, so stacked variants may no longer be intended syntax in 2.0 — but then the expected behavior would be for the engine to reject the class rather than emit invalid CSS. Either outcome (emit... and (prefers-color-scheme:dark), or treat the class as invalid) would be fine; silently generating a rule that browsers discard is the worst of both.Expected:
@media (width>=52.125rem) and (prefers-color-scheme:dark){...}— or the class is rejected as invalid.Reproduction
bun add @master/css@rc @master/css-compiler@rc @master/css-engine@rc(all resolve to 2.0.0-rc.88)master.css:repro.mjs:bun repro.mjsprints:The single-variant classes are correct; the stacked one is missing
andbetween the two media features. The same output is produced through@master/css.vitein a real build.System Informations