Scoped styles applied to child component when component has 1 root element or when used composition api
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:
- Child root component is only one
- Child root component is switched by v-if
- 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.
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.
@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
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
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).
@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:
fullIsolation
- style will newer be applied to this component from parent componentcompromiss
- only when you have 1 root item in one time (Default
). Like now.always
- always add styles to ALL root elements (no matter how many).
It very usefull when you write libs to have a choose.
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 better when "only second", but in first and second itteration its not same
if (isFirst.value) res.push(h("div", { class: "tst", key: 1 }, "first"));
if (isSecond.value) res.push(h("div", { class: "tst", key: 2 }, "second"));
This will be fixed in https://github.com/vuejs/vue-next/pull/3374