vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.78k stars 26.95k forks source link

CSS "@import <file> layer()" isn't working #55763

Open jangeroo opened 1 year ago

jangeroo commented 1 year ago

Link to the code that reproduces this issue

https://codesandbox.io/p/sandbox/next-js-css-import-layer-bug-h3j5tq

To Reproduce

  1. Create a file with some CSS declarations, e.g. theme.css
  2. In another CSS file used in the app (e.g. global.css) add @import './theme.css' layer(theme)
  3. Start the app if it's not already running

Current vs. Expected behavior

Expected behaviour: All styles from theme.css are applied.

Actual behaviour: No styles from theme.css are applied.

Verify canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.6.0: Wed Jul  5 22:22:05 PDT 2023; root:xnu-8796.141.3~6/RELEASE_ARM64_T6000
    Binaries:
      Node: 18.13.0
      npm: 8.19.3
      Yarn: N/A
      pnpm: N/A
    Relevant Packages:
      next: 13.5.3-canary.0
      eslint-config-next: 13.5.2
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.2.2
    Next.js Config:
      output: N/A

Which area(s) are affected? (Select all that apply)

Not sure

Additional context

This bug appears in both the old pages router and app router. It does not happen with a bare-bones React application created with created-react-app, where importing css layers works as expected.

hipdev commented 1 year ago

Lol, this one is fun, I can reproduce it, it looks like the layers are not working from imported files inside the app directory.

It will work if you move your theme.css file to the public directory, then import it


@import "/theme.css" layer(theme); 
fchristant commented 1 year ago

Just chipping in to share a similar experience, but in my case it looks like the statement doesn't even compile. Example:

import "react-toggle/style.css" layer(components);

Expected ';', got 'layer'

The above code does compile without the layer addition. This is a bit of a deal-breaker for working with CSS layers in Next.js, in particular when you organize your own custom CSS into layers and then import a npm package that has styles. As the styles of the npm package are not in any of your layers, they take a higher specificity than any of your layers, thus making layer order somewhat pointless.

The above syntax, if it would work, would solve that. It allows for the importing of external styles neatly into your layer order.

For now I worked around it by copying the external styles, putting them in my own styles folder and wrapping the external styles into a layer, like so:

@layer components {
... external styles here
}

The downside is of course that this breaks npm update.

Darep commented 1 year ago

For us, this was fixed by installing postcss-import, and adding it to postcss.config.js as the first plugin in plugins.

Roger322 commented 8 months ago

It also appears that any @layer rule used to specify the priority/order of the layers in the @import statements is placed/moved after the styles from the @imports. this would force the layers into order of appearance priority instead of the order dictated by @layer.

This problem is also fixed by @hipdev 's workaround so I'm unsure if this is a separate bug (that would only have a visible effect once this bug is resolved) or a symptom of the same problem.

amadeus commented 6 months ago

I've been messing around with trying to get CSS Cascade layers working with NextJS, and found some interesting things of note. If you try to do @import url() layer(someLayer); syntax, it appears that by default, NextJS bundles it like this:

@media layer(someLayer) {
  // your css
}

Which is basically invalid CSS and the selectors are essentially black hole'd. One interesting finding I did have though, is using --turbo in dev, appears to fix all these problems (although --turbo appears to have a bunch of other potential issues with it, not sure if it's considered production ready, such as not allowing composes in @layer {} definitions or sometimes converting invalid CSS values into other valid but still not what you want CSS values which took a bit of debugging to suss out.

However, all that said, when I build the bundle for prod, the broken @media layer(someLayer) {} syntax returns :(