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

Support for components being able to impact css scope #4661

Closed
bmlyon opened this issue Apr 11, 2020 · 13 comments
Closed

Support for components being able to impact css scope #4661

bmlyon opened this issue Apr 11, 2020 · 13 comments

Comments

@bmlyon
Copy link

bmlyon commented Apr 11, 2020

This issue relates to #901, which was closed in favor of sveltejs/rfcs#13, which does not address multiple problems mentioned in 901.

Problem statement

It is currently not possible in Svelte for styles within a component to impact areas outside of the component.

This impacts, among other things:

  • The ability for nested components to have styles related to the nesting.
  • The ability to have component styles be related to placement, ie if both components are on the page, style them differently.
  • The ability for stylesheets to easily impact groupings of components (ie this is my "navigation" stylesheet).
  • The ability to DRY style (I can't reuse certain styles because components can't impact eachother).
  • The ability to opt-in or opt-out of style encapsulation at any given time.
  • The ability to use the first letter in the CSS acronym, the cascade.
  • The ability to insert svelte into a legacy application with preexisting CSS.

Examples of how other frameworks work around this problem

@antony
Copy link
Member

antony commented Apr 11, 2020

@bmlyon For clarity, it's worth also answering why the following aren't suitable for your usecase:

  • Global selectors:

`:global(.any-selector .anything .anywhere)

  • Globally scoped styles:

https://github.com/kaisermann/svelte-preprocess#global-style

  • Style tags in <svelte:head>

  • Global stylesheets

Two more things I noticed from your issue which don't make sense to me:

Styles within a component are generally used to style that specific component, not other components nor that component's children. Global styles are recommended for other use-cases.

Styles from outside Svelte will impact components the same way as they would non-svelte components. It's just CSS and HTML.

@antony antony transferred this issue from sveltejs/rfcs Apr 11, 2020
@bmlyon
Copy link
Author

bmlyon commented Apr 11, 2020

I'm not interested in a global styles with all possibilities stuffed in it. That is inefficient code.

svelte-preprocess

Assumes preprocessing, which I would prefer to avoid.

Styles within a component are generally used to style that specific component, not other components nor that component's children.

This is where I disagree. Styles within a component are also used to CONTEXTUALLY style that component.

nor that component's children.

Example: a literal parent wouldn't wear a baby carrier on them unless the baby is around and needs to be carried by that individual. The presence of the baby says "hey parent X, please wear a baby carrier" and doesn't say that to both parents. Eventually one parent gets tired and can't carry the baby anymore and so they then provide that carrier to the other parent. You're saying "hey random adult, always wear a baby carrier in case you have to hold a baby" as well as "hey baby, prepare to be in a carrier that some stranger could pick up and steal you with" instead of "hey baby, only get in your parent's carrier."

@kevmodrome
Copy link
Contributor

.parentDiv :global(.classInChild) {
...
}

Would style .classInChild from your parent. The only drawback is that you might need an extra wrapping element.

@bmlyon
Copy link
Author

bmlyon commented Apr 11, 2020

.parentDiv :global(.classInChild) {
...
}

Would style .classInChild from your parent. The only drawback is that you might need an extra wrapping element.

But would that live in the parent code or child code?

@kevmodrome
Copy link
Contributor

kevmodrome commented Apr 11, 2020

@bmlyon
Copy link
Author

bmlyon commented Apr 11, 2020

The parent: https://svelte.dev/repl/0d453a581ca14d7e9373e07b6a2449a9?version=3.20.1

That's my problem. Unless the code lives in the child it can be an inefficient delivery.

Imagine you have a few dozen wrapper components into which hundreds of different child components can be inserted. Each child behaves differently depending on which parent it gets inserted into. Pretty soon each parent has code for hundreds of children, regardless of whether or not they are being loaded by the end-user. Compounding the problem, several of those parents may be present on a page at a given time. Pretty soon the page gets delivered with a significant amount more code than is needed if the child component were to specify what styles get served instead of the parent making the decision.

@kevmodrome
Copy link
Contributor

I see, you can of course do the same in reverse:

Parent:

<script>
	import Child from './Child.svelte'
</script>

<div class="tooltip-parent">
	<Child />
</div>

Child:

<style>
	:global(.tooltip-parent) .child {
		background: rebeccapurple;
		color: white;
	}
</style>

<h1 class="child">
	Child
</h1>

Example: https://svelte.dev/repl/9c2b0bcbded24ced8bd565a14b5f9b1c?version=3.20.1

@bmlyon
Copy link
Author

bmlyon commented Apr 11, 2020

This is a bad example because really I'm talking about inheritance not color, but it was the easiest way I could showcase what I mean https://codepen.io/brandonmlyon/pen/ExVaMaz

@mjgartendev
Copy link

CSS custom props offer a lot of flexibility while still cascading in a predictable manner. In any component you can create classes to explicitly override the value (even dynamically based on props with the class directive), and pseudo-selectors for contextual overrides.

Components can also apply styling based on which slot they're rendered into and can pass props around for dynamic styling.

Or a component can register with a parent context onMount, get back data it needs to style itself, update as sibling Components are mounted, and clean up onDestroy.

For sharing styles that are too specific to declare globally but aren't common enough for a dedicated Component, you could create actions to mixin chunks of style and customize with whatever data you want per instance.

Just some ideas. I know none of them are perfect but I think Svelte's constraint on things like this ultimately provides a lot of flexibility and simplicity.

@Conduitry
Copy link
Member

I don't feel like this issue made a coherent argument for adding a feature. If you have a concrete proposal, and can explain what this provides that doesn't currently exist, please open an RFC so it can be discussed with a better understanding of what you're looking for.

@AlbertMarashi
Copy link

AlbertMarashi commented May 16, 2020

This is a deal-breaker for me.

Vue supports child scoping and svelte should too.

For example, I have a <Link> component that manages javascript routing, and renders an <a> tag.

Say I want to style this javascript routing anchor tag on various pages (some may be buttons, plain links, images) it makes it incredibly difficult. Eg:

<Link href="/about">About Us</Link>
<style>
a {
  color: red; //doesn't apply this rule, because scoping doesn't extend to children
}
</style>

We should be able to apply an attribute to the style to apply scoping to child elements, eg:

<Link href="/about">About Us</Link>
<style children>
a {
  color: red; //applies rule to children
}
</style>

@istonejoeljonsson
Copy link

This is a deal-breaker for me.

Vue supports child scoping and svelte should too.

For example, I have a <Link> component that manages javascript routing, and renders an <a> tag.

Say I want to style this javascript routing anchor tag on various pages (some may be buttons, plain links, images) it makes it incredibly difficult. Eg:

<Link href="/about">About Us</Link>
<style>
a {
  color: red; //doesn't apply this rule, because scoping doesn't extend to children
}
</style>

We should be able to apply an attribute to the style to apply scoping to child elements, eg:

<Link href="/about">About Us</Link>
<style children>
a {
  color: red; //applies rule to children
}
</style>

This should only affect the direct children, and not the children inside that children then I guess?

@AlbertMarashi
Copy link

AlbertMarashi commented May 16, 2020

This is a deal-breaker for me.
Vue supports child scoping and svelte should too.
For example, I have a <Link> component that manages javascript routing, and renders an <a> tag.
Say I want to style this javascript routing anchor tag on various pages (some may be buttons, plain links, images) it makes it incredibly difficult. Eg:

<Link href="/about">About Us</Link>
<style>
a {
  color: red; //doesn't apply this rule, because scoping doesn't extend to children
}
</style>

We should be able to apply an attribute to the style to apply scoping to child elements, eg:

<Link href="/about">About Us</Link>
<style children>
a {
  color: red; //applies rule to children
}
</style>

This should only affect the direct children, and not the children inside that children then I guess?

Maybe it should be called descendants or something, but anyway, the name is not the problem, it's the missing feature

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

7 participants