Skip to content

CSS pseudo selector + nested CSS media query break in build mode #15873

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
echocrow opened this issue May 6, 2025 · 4 comments
Closed

CSS pseudo selector + nested CSS media query break in build mode #15873

echocrow opened this issue May 6, 2025 · 4 comments

Comments

@echocrow
Copy link

echocrow commented May 6, 2025

Describe the bug

Media queries nested inside a pseudo selector seem to work as-expected in dev, but break in build mode.

Contrived example:

<div></div>

<style>
div::after {
  content: 'red pls';
  @media screen {
    background: red;
  }
}
</style>

I'd expect the ::after pseudo element to have a red background when viewed on the web.

While in dev mode, this works as expected. But vite build produces this output:

div.svelte-19hj1kk:after {
    content: "red pls';"
}

@media screen {
    {
        background: red
    }
}

Expected output instead is:

div.svelte-19hj1kk:after {
    content: "red pls';"
}

@media screen {
    div.svelte-19hj1kk:after {
        background: red
    }
}

Not sure if this is a bug with Svelte, or in the Vite bundling chain(?)

The fact that this works in dev is a tad concerning; as this leaves a false impression working code, which then breaks silently during build & in prod. We only started noticing it once another processor started complaining about invalid CSS.

I tried a rollback, but seems like this was also a bug in Svelte 4. (I had not tried Svelte 3 or earlier.)

Reproduction

Stackblitz Repro (starts build && preview)

Logs

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 20.19.1 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.8.2 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    svelte: 5.28.2 => 5.28.2

Severity

annoyance

@7nik
Copy link
Contributor

7nik commented May 6, 2025

I got the same problem in a fresh vite vanilla js project. So it's vite's bug, or even esbuild's, like a similar one vitejs/vite#18974 (has a workaround in the end).

@echocrow
Copy link
Author

echocrow commented May 7, 2025

ah, I should have know better to dig deeper - thanks for the reference!

tried the suggestion in our actual repo. unfortunately that does not fix our actual issue. turns out, there seems to be a similar bug in lightningcss too: Lightning CSS repro

closing this as this is not an issue with Svetle 👋

@echocrow echocrow closed this as completed May 7, 2025
@7nik
Copy link
Contributor

7nik commented May 7, 2025

The thing is :is() cannot contain pseudo-elements

@echocrow
Copy link
Author

echocrow commented May 7, 2025

The thing is :is() cannot contain pseudo-elements

Ha! I just now learned that too while digging through Lightning CSS issues: parcel-bundler/lightningcss#937 (comment)

the odd thing is, we're not authoring the :is() selector; our source code looks like this:

.foo::after,
.bar::after {
  @media (width >= 123px) {
    color: whatever;
  }
}

we discovered the issue while migrating to Tailwind v4, which makes use of Lightning CSS. Tailwind seems to run Lightning CSS twice, and Lighting CSS appears to be wrapping the two selectors with :is() on the first pass.

So the above example gets transformed into…

@media (min-width: 123px) {
  :is(.foo:after, .bar:after) {
    color: whatever;
  }
}

…and after a second pass of Lightning CSS that becomes…

@media (min-width: 123px) {
  :is() {
    color: whatever;
  }
}

Initially I thought only the final output was incorrect. But given that pseudo selectors are not allowed inside of :is(), it seems the first pass is already a breaking transformation.

Lightning CSS REPL

(update: new issue opened)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants