svelte icon indicating copy to clipboard operation
svelte copied to clipboard

Cannot use Tailwind's `@apply` on a selector within a media query

Open alexlafroscia opened this issue 2 years ago • 2 comments

Describe the bug

It seems that you cannot use the Tailwind @apply syntax to add styles to a selector that is nested within a media query. An example use-case would be applying a Tailwind background color to the body tag for dark mode, which is currently a little challenging since <svelte:body> does not accept a class attribute.

For example, this code causes a build error

@media (prefers-color-scheme: dark) {
  :global(body) {
    @apply bg-gray-900;
  }
}

While these are fine

@media (prefers-color-scheme: dark) {
  :global(body) {
    background: red;
  }
}
:global(body) {
  @apply bg-gray-900;
}

I believe that this is the same error, but that issue was closed by the opener without a resolution

https://github.com/sveltejs/svelte/issues/6638

Reproduction

https://github.com/alexlafroscia/__demo-tailwind-mq-apply-error

Logs

end must be greater than start
Error: end must be greater than start
    at MagicString.remove (file:///Users/alexlafroscia/Code/github.com/alexlafroscia/demo-tailwind-mq-apply-error/node_modules/svelte/compiler.mjs:29632:27)
    at file:///Users/alexlafroscia/Code/github.com/alexlafroscia/demo-tailwind-mq-apply-error/node_modules/svelte/compiler.mjs:30648:26
    at Array.forEach (<anonymous>)
    at Atrule$1.minify (file:///Users/alexlafroscia/Code/github.com/alexlafroscia/demo-tailwind-mq-apply-error/node_modules/svelte/compiler.mjs:30646:27)
    at file:///Users/alexlafroscia/Code/github.com/alexlafroscia/demo-tailwind-mq-apply-error/node_modules/svelte/compiler.mjs:30801:23
    at Array.forEach (<anonymous>)
    at Stylesheet.render (file:///Users/alexlafroscia/Code/github.com/alexlafroscia/demo-tailwind-mq-apply-error/node_modules/svelte/compiler.mjs:30798:23)
    at ssr (file:///Users/alexlafroscia/Code/github.com/alexlafroscia/demo-tailwind-mq-apply-error/node_modules/svelte/compiler.mjs:28574:30)
    at compile (file:///Users/alexlafroscia/Code/github.com/alexlafroscia/demo-tailwind-mq-apply-error/node_modules/svelte/compiler.mjs:32273:15)
    at compileSvelte2 (file:///Users/alexlafroscia/Code/github.com/alexlafroscia/demo-tailwind-mq-apply-error/node_modules/@sveltejs/vite-plugin-svelte/dist/index.js:320:20)

System Info

System:
    OS: macOS 12.3.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 147.81 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.14.2 - ~/.volta/tools/image/node/16.14.2/bin/node
    npm: 8.5.0 - ~/.volta/tools/image/node/16.14.2/bin/npm
    Watchman: 2022.03.21.00 - /opt/homebrew/bin/watchman
  Browsers:
    Chrome: 101.0.4951.54
    Safari: 15.4
  npmPackages:
    svelte: ^3.44.0 => 3.48.0

Severity

annoyance

alexlafroscia avatar May 08 '22 22:05 alexlafroscia

From doing a little digging, I've noticed a few things:

  • It doesn't seem like Tailwind itself is part of the problem. As an accident, I forgot to create a postcss.config.cjs file for my demo reproduction, so Tailwind isn't even running; Svelte (or SvelteKit; I'm not sure which) seems to just choke on the @apply line within a media query
  • Nested media queries in general are not the issue; placing one @media within another @media does not cause a problem. The @apply syntax specifically within a media query is what seems to cause the error

alexlafroscia avatar May 08 '22 22:05 alexlafroscia

From what I know, it's a bad practice to use the @apply inside <style> ... </style>.

See what they say in the Tailwind Docs: https://tailwindcss.com/docs/functions-and-directives#using-apply-with-per-component-css

under-the-hood, frameworks like Vue and Svelte are processing every single

I'm not sure if this applies tough (no pun intended), since you're using it inside __layout.svelte with :global()

I would put the class directly on app.css or, preferably, app.html

<!-- app.html -->
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="icon" href="%svelte.assets%/favicon.png" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		%svelte.head%
	</head>
	<body class="dark:bg-gray-900">
		<div>%svelte.body%</div>
	</body>
</html>

heloineto avatar Aug 02 '22 02:08 heloineto

Just leaving this here in case anyone stumbles on to this thread, hopefully it might save someone the time I wasted 🤪:

I had the same issue except that I was nesting @apply inside of @screen. But as @heloineto said, avoid using Tailwind funcs inside <style> ... </style>. It sounds obvious, but my experience taught me that aside from the aforementioned reasons there is a very non-trivial performance implication as well. So if you're using Tailwind with Svelte, just to recap:

Don't

  • Use Tailwind funcs inside <style> or risk Tailwind running over and over

Do

  • Use <style> for handcrafted, component scoped CSS (if you need to)
  • Follow normal Tailwind conventions and only use the utilities inside the actual component markup (doesn't apply to OP), or ...
  • If possible, try to abstract your classes to something more generic that you can implement in tailwind.config.js or app.css
  • If it really is very specific and not suited to a component (as in the case of @alexlafroscia), you may need to go the app.css route

mattpfeffer avatar Nov 07 '22 12:11 mattpfeffer