-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Optionally scope imported CSS files to component level #7125
Comments
This would have to be some sort of preprocessor, because the core compiler just takes a single string as input and doesn't look at the filesystem at all. |
|
You can also use a postcss plugin to import local files (or sass's |
Thanks @Tropix126. I had tried using sass - and the @use syntax prior to filing the issue. My experience was that the styles remained unscoped. Also, can I ask in relation to your first comment, what would be the advantage of adding the |
In which way are you including your styles?
This was in response to your mentioning of a |
When using <style lang="scss">
@use 'carbon-components-svelte/css/g10.css';
</style> Of course, besides using Sass I also tried: <style>
@import 'carbon-components-svelte/css/g10.css';
</style> and <script context="module">
import 'carbon-components-svelte/css/g10.css';
</script> In all cases the imported styles are applied globally. |
@rodoch have you found any solution to this? I’m looking to do the same thing. I would like bootstrap to be scoped when imported |
I don't believe it's possible within the framework or with existing tools at this time. I've raised this issue as a feature request |
@rodoch I saw this plugin but haven't been able to make it work yet https://github.com/micantoine/svelte-preprocess-cssmodules it's got to be possible through some kind of preprocessing |
I made it work by using svelte-preprocess with less and wrapping a custom div element (scope) around it. I think this is what Tropix meant. There is no scope feature, but I can add a specific classname in my case. Something like this: <div class="default">
<pre><code class="language-javascript">console.log("Hello world!")</code></pre>
</div>
<div class="github">
<pre><code class="language-javascript">console.log("Hello world!")</code></pre>
</div>
<div class="solarized-dark">
<pre><code class="language-javascript">console.log("Hello world!")</code></pre>
</div>
<style lang="less">
.default :global {
@import (less) 'https://highlightjs.org/static/demo/styles/default.css';
}
.github :global {
@import (less) 'https://highlightjs.org/static/demo/styles/base16/github.css';
}
.solarized-dark :global {
@import (less) 'https://highlightjs.org/static/demo/styles/base16/solarized-dark.css';
}
.atelier-seaside-light :global {
@import (less) 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/atelier-seaside.light.min.css';
}
</style>
|
needed feature to make reusing styles across different component less of a hassle. EDIT: apparently <style src="./style.css"></style> Everything from |
This is a great solution - many thanks! I think that closes this issue. |
Unfortunately, you cannot use multiple For those who want to do that, I've written a rudimentary CSS preprocessor: import MagicString, {Bundle} from "magic-string";
import * as path from "path";
import * as fs from 'node:fs/promises';
/* Make `@import "./whatever.css" scoped;` statements import CSS into the component's CSS scope */
function importCSSPreprocess() {
async function importCSS({ content, filename }) {
function matchAllImports(str) {
const globalRegex = /@import\s+(".*"|'.*')\s+scoped\s*;/g;
const matches = [];
let match;
while ((match = globalRegex.exec(str)) !== null) {
const start = match.index;
const end = start + match[0].length;
matches.push({ start, end, file: match[1].substring(1, match[1].length - 1) });
}
return matches;
}
const imports = matchAllImports(content);
if(imports.length > 0) {
let lastStart = null;
const state = new MagicString(content, { filename });
const remove = (start, end) => state.clone().remove(start, end);
let out = [];
const deps = [];
for(const { start, end, file } of imports.reverse()) {
// Right
if(lastStart != null) {
out.push(remove(lastStart, content.length).remove(0, end));
} else {
out.push(remove(0, end));
}
const absPath = path.join(path.dirname(filename), file);
deps.push(absPath);
const text = (await fs.readFile(absPath)).toString();
out.push(new MagicString(text, { filename: absPath }));
lastStart = start;
}
// Left
const first = remove(lastStart, content.length);
const bundle = new Bundle();
bundle.addSource(first);
for(let i = out.length - 1; i >= 0; i--) {
bundle.addSource(out[i]);
}
return {
code: bundle.toString(),
map: bundle.generateMap(),
dependencies: deps
};
} else {
return {code: content};
}
}
return { style: importCSS }
} You can add it to your export default {
preprocess: [
importCSSPreprocess(), // <--
svelteAutoPreprocess(),
],
}; Now you can use For example, the following CSS: <style>
@import "./a.css" scoped;
@import "./b.css" scoped;
.another-style { display: block }
</style> will get converted into: <style>
contents of a.css will be here
contents of b.css will be here
.another-style { display: block }
</style> |
@null-dev thank you so much! it's worth publishing as a package. After some headscratching, got it running in webpack + svelte-preprocess: {
test: /\.svelte$/,
use: {
loader: 'svelte-loader',
options: {
// stuff
preprocess: [
// @ts-ignore
importCSSPreprocess(),
SveltePreprocess({
sass: true,
scss: true
}),
],
},
},
}, |
Nice preprocessor ! coz this is useful, I uploaded it to jsr as a package! |
Console:
HMR error overlay:
Would there be a workaround for this? Would love to use scoped global styles. |
FYI We can use css modules out of the box with rsbuild |
Describe the problem
Currently, when stylesheets are imported within either a
script
orstyle
block within a Svelte component their styles are applied globally.This is a sensible default behaviour. Some design system libraries etc. need to touch things like the
body
andhtml
elements.However, I think this can also be problematic and a limitation in some cases. For example, if you are producing a component library you often want to make sure that all of your styles are encapsulated and do not wreak havoc with the parent webpage/app styling.
Describe the proposed solution
A solution for this currently exists in Vue, where you can do something like:
...and it wil scope the contents of the CSS file. This is very ergonomic.
I want to be clear, the extent of this request is in relation to imported external CSS files. In researching this issue, I came across some rather in-depth debates as regards providing a
scoped
/unscoped
modifier for thestyle
block. I am not trying to rehash this debate here and I'm not wedded to this particular approach, I'm just using it as an example of an equivalent functionality in another popular framework.Futhermore, given that Svelte does not wrap components in a generic div in the generated HTML I can see reasons why this may be difficult to implement. But given the potential benefits for users I thought I should ask the question at least.
Alternatives considered
Importance
would make my life easier
The text was updated successfully, but these errors were encountered: