Skip to content

Scoped styles applied to child component when component has 1 root element or when used composition api #3382

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

Closed
mixalbl4-127 opened this issue Mar 7, 2021 · 10 comments
Labels
🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. 🐞 bug Something isn't working

Comments

@mixalbl4-127
Copy link

Version

3.0.7

Reproduction link

https://codesandbox.io/s/nice-bas-xpf2b?file=/src/components/HelloWorld.vue

Steps to reproduce

Open: https://codesandbox.io/s/nice-bas-xpf2b?file=/src/components/HelloWorld.vue

see that the same logic works different depended on compostion api or count of root element.

What is expected?

<style scoped>
.tst {
  background: red;
}
</style>

background: red; must never be applied to child component class

What is actually happening?

class .tst applied to child components when:

  1. Child root component is only one
  2. Child root component is switched by v-if
  3. Child root component used composition API for adding second, third etc elements to DOM (in this case only FIRST element got background: red;)

scoped styles must never be applied to child compontens OR at least always (no matter it used composition api or have 2-3-5 root childs), we need clear login like "always works like this" or "newer works like this"

When used Composition api for SWITH (like v-if) - first DOM element will have background: red; but second - no. Its extra strange because I have only 1 root element in one time (like v-if) but second elemen doest get style.

@LinusBorg
Copy link
Member

the first two examples are expected, even though they are admittedly non-ideal. Why:

In Vue 2, every component had a root node, and scoped styles were specifically designed to also be apply-able to a child component's root node in order to control .e. it's positioning from the parent.

However in Vue 3, we know have Fragments - components are no longer guaranteed to have a root node. The compromise that was reached for the Migration story was that styles could only apply to components that actually guarantee to have a rood node. In your second example, there's a second root node, that is simply never shown because of v-if="false", but the static analysis during compilation doesn't take care fo that because it's a nonsensical instruction in "real life" to have a static false value for v-if.

The third example however should be seen as a bug, imho.

@LinusBorg LinusBorg added 🐞 bug Something isn't working 🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. labels Mar 8, 2021
@Kingbultsea
Copy link
Contributor

The third is also fragment too, Why is it a bug...

@LinusBorg
Copy link
Member

Because the style is applied, when it shouldn't be applied to fragments at all.

@mixalbl4-127
Copy link
Author

mixalbl4-127 commented Mar 8, 2021

@Kingbultsea
The 3rd example is definitely a bug, since the SAME code written in the traditional style through and through the Composition API behaves differently (the traditional one does not add style at all, but the Composition API adds it to the first element)
In addition, if you replace 1 element with another (in this case there will be only 1 root component on the page (imitation of v-if), the styles will be on the first block, and when it changes to another, they will no longer be there. bug and started).

@LinusBorg
image

In this case, I think it is worth mentioning this in the manual, since at the moment it is very difficult to come to this conclusion after reading the manual.
Usually, developers think in components, there is a.vue and b.vue component, and styles from one to another, judging by the manual that are now, should never be included. But as we now know, this is not so :)
In addition, this behavior can be problematic, for this it may be worth making a special key as inheritAttrs and name it noRootStyle, by setting it to false we will disable this mechanism

@LinusBorg
Copy link
Member

LinusBorg commented Mar 8, 2021

In this case, I think it is worth mentioning this in the manual, since at the moment it is very difficult to come to this conclusion after reading the manual.

A few paragraphs down the same manual page:

https://vue-loader.vuejs.org/guide/scoped-css.html#child-component-root-elements

With scoped, the parent component's styles will not leak into child components. However, a child component's root node will be affected by both the parent's scoped CSS and the child's scoped CSS. This is by design so that the parent can style the child root element for layout purposes.

That's the Vue 2 behavior I was mentioning (vue-loader docs are still vor v15 (which is for Vue 2).

@mixalbl4-127
Copy link
Author

@Kingbultsea
https://codesandbox.io/s/blissful-stallman-zdne1?file=/src/components/HelloWorld.vue

new example betwean same logic in tradition and composition API style.

@LinusBorg
ok, I understood. But my suggestion is to enable manual control of this behavior. Example:

new scopedStyleStrategy key with 3 new value:

  1. fullIsolation - style will newer be applied to this component from parent component
  2. compromiss - only when you have 1 root item in one time (Default). Like now.
  3. always - always add styles to ALL root elements (no matter how many).

It very usefull when you write libs to have a choose.

@mixalbl4-127
Copy link
Author

Some thoughts: I think you will not be able to make the same logic for the Composition API, since the compiler cannot know how many root components will be returned until the component is mounted. It is not up to the compiler to decide during the build process.

@Kingbultsea
Copy link
Contributor

try if (isSecond.value) res.push(h("div", { class: "tst", key: 1 }, "second"));

@mixalbl4-127
Copy link
Author

mixalbl4-127 commented Mar 8, 2021

@Kingbultsea better when "only second", but in first and second itteration its not same
Peek 2021-03-08 10-22

  if (isFirst.value) res.push(h("div", { class: "tst", key: 1 }, "first"));
  if (isSecond.value) res.push(h("div", { class: "tst", key: 2 }, "second"));

@HcySunYang
Copy link
Member

This will be fixed in #3374

@github-actions github-actions bot locked and limited conversation to collaborators Oct 24, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. 🐞 bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants