Skip to content

Option to emit CSS Module <style> tags after js-imported CSS #19797

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

Open
4 tasks done
functasti opened this issue Apr 5, 2025 · 4 comments
Open
4 tasks done

Option to emit CSS Module <style> tags after js-imported CSS #19797

functasti opened this issue Apr 5, 2025 · 4 comments

Comments

@functasti
Copy link

functasti commented Apr 5, 2025

Description

In CSS, the first occurrence of a @layer name establishes its position in the cascade. If an explicit @layer ordering is declared after a declaration, that earlier declaration takes precedence—even if the later ordering includes the layer name.

Example:

<style>
  @layer components {
    div {
      color: red;
    }
  }

  @layer theme, base, components;

  @layer base {
    div {
      color: green;
    }
  }

  @layer theme {
    div {
      color: blue;
    }
  }
</style>

<div>Test</div>

The above renders the text in green because components was already defined before the ordering. If we move the @layer components block after the @layer ordering declaration, it renders in red as expected.

This behavior also applies when layers are split across multiple <style> tags.

In Vite (v6.2.0) development mode, CSS Modules are injected first, followed by JS-imported CSS. This means that any @layer declarations in CSS Modules will lock in their position before the @layer ordering declared in regular CSS, breaking the expected cascade behavior.

Suggested solution

Please add an option to render <style> tags from JS-imported CSS before those from CSS Modules, to allow proper @layer ordering to take effect.

Alternative

No response

Additional context

No response

Validations

@sapphi-red
Copy link
Member

It is working for me in both dev and build. Changing the order of the imports is correctly changing the behavior (red to green).
https://stackblitz.com/edit/vitejs-vite-13bucapn?file=src%2Fmain.js&terminal=dev

Copy link

github-actions bot commented Apr 7, 2025

Hello @functasti. Please provide a minimal reproduction using a GitHub repository or StackBlitz. Issues marked with needs reproduction will be closed if they have no activity within 3 days.

@functasti
Copy link
Author

@sapphi-red You're right—my bad. I should've provided a reproduction earlier.

I encountered the issue in a React app.

Here's my index.jsx:

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";
import './main.css';

createRoot(document.getElementById("app")).render(
  <StrictMode>
    <App />
  </StrictMode>
);

The @layer component in question is used within a nested component. Apparently, I didn’t think much about the import order.

This works as expected:

import './main.css';
import App from "./App.jsx";

It would be great if there were some kind of warning for this, since it’s such an easy thing to overlook. Or maybe even an option to ensure CSS modules are always loaded last, regardless of import order? But I don’t think this is necessarily a "problem" in Vite.

@sapphi-red
Copy link
Member

It would be great if there were some kind of warning for this, since it’s such an easy thing to overlook.

I'm not sure if Vite can detect if the import order is intended. Do you have any ideas how Vite can detect that?

Or maybe even an option to ensure CSS modules are always loaded last, regardless of import order?

I think that should be checked by a linter. Adding an option that bends the semantics to be different doesn't sound right to me.

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