A Parent component should have the ability to overwrite a child components style when both components only have scoped
styles.
Currently there is no way to overwrite a child components css style with scoped styling.
Angular2 has a selecor called /deep/
, It would be nice to have a similar feature in Vue
```/deep/
Component styles normally apply only to the HTML in the component's own template.
We can use the /deep/ selector to force a style down through the child component tree into all the child component views. The /deep/ selector works to any depth of nested components, and it applies both to the view children and the content children of the component.
In this example, we target all
COPY CODE
:host /deep/ h3 {
font-style: italic;
}
The /deep/ selector also has the alias >>>. We can use either of the two interchangeably.
The /deep/ and >>> selectors should only be used with emulated view encapsulation. This is the default and it is what we use most of the time. See the Controlling View Encapsulation section for more details.
```
https://angular.io/docs/ts/latest/guide/component-styles.html#!#sts=%2Fdeep%2F
Can you elaborate a bit on your case? I'm curious about it. The main case I can think off are sub-components like Menu > MenuItem. Although I'd apply the BEM methodology in that situation.
What is stopping you from using a CSS methodology like BEM in that specific case?
For your own components, one should prefer passing in props to change the component's behavior.
If it's a third party component, then I guess I could see the use case, since you can't edit the source of it very intuitively.
Lets take the menu > menuItem
example. Menu has a list of child menuItem components. See the below code snippet.
Now if you have 2 different components that use menu-item components on the page and you want to style the menu-items differently on the page.
Using global styles (not scoped) in the menu component (parent) will also change the style of the 2nd menu item on the page unless some other unique identifier is used to scope the styles.
Nothing is stopping me from using BEM, but why use it when there are scoped styles that can solve the problem.
----------- vmenuMain parent component ------------
<template>
<div class="menu">
<vmenuItem v-for="item in menuList" :name="item"></vmenuItem>
</div>
</template>
<script>
import vmenuItem from './menuItem';
export default {
name: 'vmenuMain',
components: {
vmenuItem,
},
data() {
return {
menuList: ['Home', 'Menu', 'Location']
};
},
};
</script>
<style lang="scss" scoped>
.menu {
border: 5px solid black;
}
</style>
<style lang="css">
//overwrite child component's css
.menu-item {
background: red !important;
</style>
---------------- Child component vmenuItem ---------------------
<template>
<a href="http://www.google.com" class="menu-item"> {{name}}</a>
</template>
<script>
export default {
name: 'menuItem',
props: [
'name',
],
};
</script>
<style lang="css" scoped>
.menu-item {
background: blue;
}
</style>
Going off that example above ^ I would also like to avoid using the !important
rule.
What if Vue allowed you to declare which child component's style you want to overwrite and it injected that specific <style>
block below the child components style in the <head>
so it became more important because of the order.
----Parent Component -----
<Style scoped>
// Parent styles
</style>
//this will be injected below child component's styles in the head of the document
//which will allow you to easily overwrite a child components style
<style scoped child-component="menuItem">
//styles that overwrite child component
</style>
Nothing is stopping me from using BEM, but why use it when there are scoped styles that can solve the problem.
BEM and scoped style solve different problems. Scoped allows style encapsulation while BEM is a methodology
I would have preferred another example other than the Menu/MenuItem. Using classes to override a style works fine, no need to use !important
:
// MenuItem.vue
<template>
<li class="item">
<slot></slot>
</li>
</template>
<style scoped>
.item {
color: blue;
}
</style>
// Menu.vue
<template>
<ul class="red">
<slot></slot>
</ul>
</template>
<style scoped>
.red .item {
color: red;
}
</style>
You can, of course, add that rule in a component using Menu instead of the menu itself
Yes, that example will work for the first child of the component, but if menuItem had another component inside of it called vbutton
then we can't modify vbutton's
style (from Menu) since it does not contain the Menu's unique ID as an attribute.
/deep/
was usedI tested and it worked well...
I'm curious, do you have a different case that cannot be solved with a CSS methodology?
Did you try it with 3 components? I posted an example with 3 components and I wanted to style the button component which was the most deeply nested component which I couldn't overwrite the scoped style from the root component. Maybe I am doing something wrong? (I am only using scoped styles avoiding global styles on purpose)
@agaripian Yes, here's what I tested: https://gist.github.com/posva/53dd9e16d72acfcaa9476e4348b903e1
@posva Your example is working because you are using <slot>
in the 2nd component menuItem
and you are importing the button into the root Menu
component. In my example, button is imported by the menuItem
component so its nested inside the 2nd level component.
Here is my example:
https://gist.github.com/agaripian/271f0d58d4db3601b2e0d0f3dffe3459
It still works that case, adding a style
without scoped
and making sure the specificity of the selector is higher by adding one class is enough.
Letting the Menu, items aside, I'm more interested in a different case that cannot be solved with a CSS methodology?
Here is a working example that I put together from our existing websites functionality converted to Vue components. I used a Global Style on the Root component which did not work.
https://gist.github.com/agaripian/7b430d1ffa3b360c4709010e7013675c
Profile
> followButton
> button
Button
and followButton
have scoped styles.
Profile
uses Global styles to overwrite children
followButton
overwrites button
styles.
Profile
can not overwrite button's
background color.
/deep/
adds the unique ID attribute selector from component that is using /deep/
. I manually added the the unique id attribute of Profile
to its style selector and it solved the problem as well as scoped it properly. It also automatically makes the selector more specific so we can avoid !important. (see blue highlight below)I want to avoid using Global styles so we can truly scope our css. I can probably find another way of adding some more specific css selector but that just complicates development and debugging.
Moving this to https://github.com/vuejs/vue-loader/issues/661
Most helpful comment
Here is a working example that I put together from our existing websites functionality converted to Vue components. I used a Global Style on the Root component which did not work.
https://gist.github.com/agaripian/7b430d1ffa3b360c4709010e7013675c
Profile
>followButton
>button
Button
andfollowButton
have scoped styles.Profile
uses Global styles to overwrite childrenfollowButton
overwritesbutton
styles.Profile
can not overwritebutton's
background color.Can not overwrite background color
Angular2 with
/deep/
adds the unique ID attribute selector from component that is using/deep/
. I manually added the the unique id attribute ofProfile
to its style selector and it solved the problem as well as scoped it properly. It also automatically makes the selector more specific so we can avoid !important. (see blue highlight below)I want to avoid using Global styles so we can truly scope our css. I can probably find another way of adding some more specific css selector but that just complicates development and debugging.