Skip to content
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

Recessive CSS rules #6859

Closed
janosh opened this issue Oct 19, 2021 · 14 comments
Closed

Recessive CSS rules #6859

janosh opened this issue Oct 19, 2021 · 14 comments

Comments

@janosh
Copy link
Contributor

janosh commented Oct 19, 2021

Describe the problem

Every CSS rule applied internally to a component that you want to override from the outside with global CSS requires the !important keyword. See REPL.

Describe the proposed solution

Recessive CSS rules, i.e. rules with lowest possible specificity no matter with what selector they were set with inside the component.

Not sure what's the word to use here. Just using recessive in the style of genes where the dominant allele is the one expressed in the phenotype while recessive alleles are masked.

Such rules could be placed inside a special scope (similar to :root {}) or perhaps applied through a class with a special keyword so the svelte compiler knows to apply these rules with low specificity.

Alternatives considered

Creating CSS variables for every CSS rule in a component gets old fast. Plus changing these CSS props is quite verbose. E.g. to specify just four colors:

<MultiSelect
  --sms-options-bg="white"
  --sms-li-active-bg="cornflowerblue"
  --sms-li-disabled-bg="gray"
  --sms-readonly-bg="lightgray" />

Importance

would make my life easier

@Conduitry
Copy link
Member

Would would this compile to in the output CSS for a component? We're limited by what's actually supported in CSS, and there's nothing like !unimportant in CSS as far as I know.

@TheOnlyTails
Copy link

TheOnlyTails commented Oct 19, 2021

It exists, and it's called the :where selector. It has 0 specificity, and can be overrided by any other selector.

@Conduitry
Copy link
Member

Does :where() itself make sense to be what you'd use for this feature then? Right now, :where(.par) compiles to .svelte-123:where(.par), which isn't helpful in this case. If that compiled to :where(.par.svelte-123) that would suffice for this I think.

The question then is whether making that change would be considered breaking. Probably technically, but I'm also having a hard time imagining anyone depending on the current .svelte-123:where(.par) behavior for anything practical.

@janosh
Copy link
Contributor Author

janosh commented Oct 19, 2021

@TheOnlyTails made an excellent point here!

Does :where() itself make sense to be what you'd use for this feature then?

Using :where() itself would probably work but seems less succinct and in particular less semantic than it could be.

Screen Shot 2021-10-19 at 20 05 54

I assume Svelte's policy on CSS is that anything inside the style tag must parse as valid CSS, i.e. we can't define any new keyword or syntax?

@TheOnlyTails
Copy link

Assuming the CSS scoping system works like I think it does, if you insert each selector into the :where selector after being added the scoping class, it should work just fine.

@janosh
Copy link
Contributor Author

janosh commented Oct 19, 2021

I just tried this out and what's odd is the REPL and the latest SvelteKit v1.0.0-next.186 seem to behave differently here.

In the REPL, the local styles even wrapped in :where() take precedence. But in SvelteKit, the outside :global() styles take effect.

@dummdidumm
Copy link
Member

If this is changed, it could be regarded as a breaking change since people may rely on this, consciously or not.

@Monkatraz
Copy link

If you want a verbose workaround, you can avoid the use of !important by making your global CSS selector more specific:

.foo.foo {
  color: red;
}

I'm not saying that this is a good alternative, just that it doesn't use !important. In general, Svelte has trouble supporting external theming and I do wish there were more options for tweaking Svelte's CSS output. Personally, I wouldn't mind <style global> to just not have CSS hashing, but the :where solution is pretty clever.

@janosh
Copy link
Contributor Author

janosh commented Oct 20, 2021

So how about a having a new style tag

<style context="fallback">
  color: red
</style>

similar to how there are two types of script tags (<script context="module">) where every CSS rule in this <style> block would be wrapped in :where() (after hashing) to make it easily overridable? That would not be a breaking change and would make component styling easier imo.

janosh added a commit to janosh/svelte-multiselect that referenced this issue Oct 21, 2021
@dsebastien
Copy link

I'm not sure it is related, but I currently face an issue when trying to integrate daisyUI in my Svelte application. daisyUI uses this syntax: *:where(.btn),:global(.mockup-code),:global(.mockup-window),:global(.badge),:global(.card), which causes a compilation error with Svelte: Error during bundle: :global(...) must contain a single selector.

@janosh
Copy link
Contributor Author

janosh commented Oct 22, 2021

@dsebastien See #6434.

@rcmangnale

This comment has been minimized.

@janosh
Copy link
Contributor Author

janosh commented Jan 15, 2024

@dummdidumm @Conduitry Is a solution to this still on the table for Svelte v5? E.g. by changing the way :where() is compiled as suggested above by @Conduitry?

@Rich-Harris
Copy link
Member

Svelte 5 uses where(...) alongside class scoping (details in #10443) for a predictable specificity bump, which can reliably be overridden from outside, so I'll close this

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

8 participants