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

SFC scoped style improvements #94

Open
yyx990803 opened this issue Nov 8, 2019 · 66 comments
Open

SFC scoped style improvements #94

yyx990803 opened this issue Nov 8, 2019 · 66 comments

Comments

@yyx990803
Copy link
Member

We are aware that the current SFC scoped style implementation has a number of issues/limitations regarding the component root node and slotted content. I'd like to use this thread to collect feedback and help us improve the scoped style implementation.

What are the pain points when using <style scoped>? What features you hope <style scoped> could support? We have some ideas, but we'd like to hear from the users to get a clearer picture. If you have ideas or suggestions, please provide feedback here (and please be as specific as possible, with code samples and clear descriptions of your scenario).

@blake-newman
Copy link
Member

The main issue we face is with multiple nested functional components, scoping doesn't seem to apply.

Removing that limitation itself removes tonnes of limitation

@parker-codes
Copy link

Scoped by default. It would not be backwards compatible unless there were a configuration flag. I think it is beneficial because I've never had a component that wasn't scoped. I put global styles in an actual CSS file at the top level.

@michaeldrotar
Copy link

This is interesting.. I've never used scoped and instead rely on BEM-like naming conventions to avoid collisions.. this affords me the flexibility for a parent component to tweak its children's styles with actual css rather than creating all kinds of attributes that provided limited customization.

I thought this was the intended usage given this note: Scoped styles do not eliminate the need for classes.
https://vue-loader.vuejs.org/guide/scoped-css.html#also-keep-in-mind

@nblackburn
Copy link

nblackburn commented Nov 8, 2019

Scoped by default. It would not be backwards compatible unless there were a configuration flag.

There is an alternatives to scoped css (css modules, css in js etc...) so this cannot be a default option without conflicting against those alternatives.

@Wharley01
Copy link

Making SCSs the default, then generating a unique class per component to wrap around all classes in that component,


Advantage is,

A more cleaner html will be generated(html might not be touched)

This is actually the real scoping

The class generated for each component may follow a pattern which developer can manually target

@hollandThomas
Copy link

There are several CSS-in-JS libraries in the React ecosystem that offer a couple of nice features. styled-components, for example, lists compelling points in its motivation.

Especially, I always wondered whether Vue could provide something along those lines:

  • Simple dynamic styling: adapting the styling of a component based on its props or a global theme is simple and intuitive without having to manually manage dozens of classes.

Of course, you can bind styles to a computed property in Vue but having the computation and adaption of styles right inside of a styled-component always made more sense to me personally.

Instead of passing classes for styles, those components are in fact really _just components_™ and are accessed like any old component: by its name. That makes templates more readable IMO. Also, having a global theme (with colors, spacings et al.) at hands inside of such structures often comes in handy.

There are adapters for e.g. emotion but it would be really cool to have something like this "battery included" in Vue itself. I'm definitely not saying to replace the current way of doing things but instead to take a look into the ideas as I'm convinced they have a lot to offer.

@IlCallo
Copy link

IlCallo commented Nov 8, 2019

Coming from an Angular background, a thing I really miss in Vue SFC is the :host selector.
95% of time I need to stile the root component, having to define a class every time is just annoying...

@logaretm
Copy link

logaretm commented Nov 8, 2019

A few things I have in mind:

  • Ability to target root nodes with a custom selector, I believe angular is doing that.
  • It could be worth making scoped styles are the default as it is extremely unlikely to have a component targeting styles for other components and should be discouraged as well, I have built quite a few apps over the past years and never I have not used scoped styles.
  • If we can find a better alternative than the data-* selectors that would be great, maybe even make it predictable like a wrapper class name equal to the name of the component.

@hecktarzuli
Copy link

hecktarzuli commented Nov 8, 2019

We should consider moving attribute selectors to simple class selectors
button.hash vs button[hash]

I haven't tested it, but I believe attribute selectors are some of the slowest around.

image

@nblackburn
Copy link

If we can find a better alternative than the data-* selectors that would be great.

We should consider moving attribute selectors to simple class names
button.hash vs button[hash]

@hecktarzuli, @logaretm @Wharley01 You can use CSS modules if you are like me and don't like data attributes polluting the DOM and exposing the underlying framework.

@logaretm
Copy link

logaretm commented Nov 8, 2019

@nblackburn I'm fine with them making my DOM ugly, also I wouldn't care about ppl finding out my framework of choice. I'm only concerned by the selector performance which @hecktarzuli has illustrated.

@4refael
Copy link

4refael commented Nov 8, 2019

I never liked scope style my components because I usually needed to reuse some of the stylings in other places. Also, CSS is hard to maintain and have pieces of it in each component wasn't ideal for me.
I then started using utility-first css, and I longer feel like I need css in SFC anymore.

@Rolanddoda
Copy link

I don't know if its currently available or if it's doable but it would be great to reactively use CSS variables in the template.

<template>
   <div :class="background: '--chosen-bg'"></div>
</template>

@hecktarzuli
Copy link

hecktarzuli commented Nov 8, 2019

💥 The main problem with Vue styles is it's hard to have reusable styles that are only loaded when they are needed.

It seems pretty darn hard to write style XYZ, and that's used by 5 components without shoving it somewhere global (which forces it to be loaded even when it's not needed)

@yyx990803 if you could find a way to make reusable styles that are required by components, but only loaded once, on-demand, that would be huge step forward.

@michaeldrotar
Copy link

michaeldrotar commented Nov 8, 2019

I don't know if its currently available or if it's doable but it would be great to reactively use CSS variables in the template.

<template>
   <div :class="background: '--chosen-bg'"></div>
</template>

You can do things like this:

<div style="--some-color: blue"></div>
div {
  color: var(--some-color, 'red');
}

Replace style with a :style="myStyles" binding, make myStyles a computed to combine multiple attributes into css variables, and then good to go.

Personally I think it's alot easier to not used scoped css and just use normal css to target and change styles as needed -- but this is a flexible option for people that want it.

More info:

@casey6
Copy link

casey6 commented Nov 8, 2019

I haven't tested it, but I believe attribute selectors are some of the slowest around.

Didn't this stop being a real problem ages ago? Performance is certainly important, but I'd like to see some actual data to back up that claim.

@chris-visser
Copy link

Would be nice to somehow be able to inject reactive variables using for example a 'style' property on the vie component. I find the above example a bit cumbersome. We could do something like this:

<script>
export default {
  styles() {
    return {
      $primary: '#222266'
    }
  }
}
</script>

<style>
.btn {
  background-color: $primary;
}
</style>

We could make it behave the same as computed variables. It would be very powerful to have design systems inject their variables to for example a theme component

@ThomasWT
Copy link

ThomasWT commented Nov 8, 2019

I used to think that scoped means that it would only apply to the component, that it was used in. But it does not. Sometimes it removes the css from the component instead. Either improve documentation or behavior.

ezgif-2-906ed815a0ca 1

@nblackburn
Copy link

nblackburn commented Nov 8, 2019

I used to think that scoped means that it would only apply to the component, that it was used in. But it does not. Sometimes it removes the css from the component instead. Either improve documentation or behavior.

ezgif-2-906ed815a0ca 1

@ThomasWT You have global selectors like html in that code which will not work with scoped css.

@ThomasWT
Copy link

ThomasWT commented Nov 8, 2019

I used to think that scoped means that it would only apply to the component, that it was used in. But it does not. Sometimes it removes the css from the component instead. Either improve documentation or behavior.
ezgif-2-906ed815a0ca 1

You have global selectors like html in that code which will not work with scoped css.

Will that remove most, if not all the CSS?

@nblackburn
Copy link

nblackburn commented Nov 8, 2019

I used to think that scoped means that it would only apply to the component, that it was used in. But it does not. Sometimes it removes the css from the component instead. Either improve documentation or behavior.
ezgif-2-906ed815a0ca 1

You have global selectors like html in that code which will not work with scoped css.

Will that remove most, if not all the CSS?

If you don't organise your CSS correctly then yes. The CSS must be specific to the component it is defined in for it to work. Global styles will need to be defined elsewhere.

@Meekohi
Copy link

Meekohi commented Nov 8, 2019

I personally have found it to be a very good trade-off using scoped styles, even though it means duplicating CSS many times between components (find/replace across files is fairly practical for making consistent changes if you use smart naming conventions).

In contrast getting the same dynamic styles to be consistent across many components feels painful. In our case, individual customers set themes/colors that apply across many components: we end up injecting their config into global JS and then using a mixin to construct the correct CSS styles in various components, bypassing the scoped classes (which feels like where this should actually go) and injecting the dynamic styles directly on the DOM elements.

@CyberAP
Copy link
Contributor

CyberAP commented Nov 8, 2019

Use class prefixing as a scoping mechanism instead of attributes?
That would remove performance penalty in runtime. Dynamic classes could be implicitly prefixed in runtime.

Also render functions are left out of this feature, maybe something could be improved in that regard?

@ahtee
Copy link

ahtee commented Nov 8, 2019

For backwards compatibility, there could be v-bind:style for those still using it, but a new vue directive for default, component-scoped css like v-style which can take an object or template literals like styled-components so it can have conditionals in the css itself. 🙂

Was thinking this because v-bind can move more towards data instead of the design of a component as well.

Then anything in <style> or Could imply that styles are component scoped by default without being explicit about scope

@NvdB31
Copy link

NvdB31 commented Nov 8, 2019

I’d like to see a way to use dynamic styles other than relying on a predefined :class binding or :style binding.

I know this can be done with CSS-in-JS libraries like Vue-styled-components, but none of them seem to have solid support for Vue.

@alex-lit
Copy link

alex-lit commented Nov 8, 2019

Please tell (in documentation) about the >>> operator, many developers do not know about its existence, but it solves almost all problems with scoped styling.

@hecktarzuli
Copy link

hecktarzuli commented Nov 8, 2019

Please tell (in documentation) about the >>> operator, many developers do not know about its existence, but it solves almost all problems with scoped styling.

@alex-lit It's in the vue-loader docs
https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors

@alex-lit
Copy link

alex-lit commented Nov 8, 2019

I’d like to see a way to use dynamic styles other than relying on a predefined :class binding or :style binding.

I know this can be done with CSS-in-JS libraries like Vue-styled-components, but none of them seem to have solid support for Vue.

How about css variables?

<template>
  <section class="my-component" :style="`--my-var: ${myVar};`">
    <span>
      Hello, World!
    </span>
  </section>
</template>

<script>
export default {
  data() {
    return {
      myVar: 'red',
    };
  },

  mounted() {
    setTimeout(() => {
      this.myVar = 'green';
    }, 1000);
  },
};
</script>

<style>
.my-component {
  position: relative;
  display: flex;
  width: 100vw;
  height: 100vh;
  align-items: center;
  justify-content: center;
  background-color: var(--my-var);
  color: white;
  font-family: monospace;
  font-size: 48px;
  transition-duration: 1s;
}
</style>

@rico-ocepek
Copy link

rico-ocepek commented Nov 8, 2019

Deterministic scoped selectors values would be great, maybe even a way to define how the data-v value should be calculated. The webpack css-loader enables us to do so for CSS modules with their localIdentName option.
Would be nice to see this for Vue scoped styles too.

This comes in handy when you have multiple webpack jobs that should produce compatible style / components.

@korkies22
Copy link

korkies22 commented Nov 8, 2019

The most challenging problem I face is when I use a library which has its own scoped styles (or even my own components). Trying to modify the default styles of those components is truly a big pain for me.
I also think that as css houdini and some other people here propose, the future will be js in css. It would really be useful to use variables declared in script in the style section

@dennzimm
Copy link

dennzimm commented Nov 9, 2019

scoped by default would be nice ;-)
Maybe include a global flag to change mode from scoped to global.

@rico-ocepek
Copy link

@korkies22 @crrobinson14 @paulrosen

Hi guys, not sure if you are aware of this but there is something called the "deep selector". When using scoped styles it can be used to also target child elements.
Just use /deep/ or >>>

eg. .mycomponent /deep/ .child a { color: red; }

https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors

@NvdB31
Copy link

NvdB31 commented Nov 9, 2019

I’d like to see a way to use dynamic styles other than relying on a predefined :class binding or :style binding.
I know this can be done with CSS-in-JS libraries like Vue-styled-components, but none of them seem to have solid support for Vue.

How about css variables?

<template>
  <my-component class="my-component" :style="`--my-var: ${myVar};`">
    <span>
      Hello, World!
    </span>
  </my-component>
</template>

<script>
export default {
  data() {
    return {
      myVar: 'red',
    };
  },

  mounted() {
    setTimeout(() => {
      this.myVar = 'green';
    }, 1000);
  },
};
</script>

<style>
.my-component {
  position: relative;
  display: flex;
  width: 100vw;
  height: 100vh;
  align-items: center;
  justify-content: center;
  background-color: var(--my-var);
  color: white;
  font-family: monospace;
  font-size: 48px;
  transition-duration: 1s;
}
</style>

This is a solution, but requires all properties to be defined beforehand. For my specific use-case (a WYSIWYG builder with stylable nodes) this isn't desirable.

@MDSLKTR
Copy link

MDSLKTR commented Nov 9, 2019

In general i like to use scoped styles a lot but in cases with content rendered by v-html when for instance integrating widgets from prerendered sources, the scoped styles won‘t propagate all the way down. So we mostly use a custom directive (https://github.com/pixolith/vue-packages/tree/master/packages/vue-raw-html) for that. So for this use case it would be nice to have the option to apply scoped attributes to dynamic children.

@egoist
Copy link

egoist commented Nov 9, 2019

Scoped by default and providing a native way to use CSS in JS are my two wishes, I implemented them via a custom vue template compiler: https://github.com/egoist/styled-vue 🤔

@MatteoNY
Copy link

MatteoNY commented Nov 9, 2019

How about adding <style isolated> that would do what css modules do without the extra syntax/code. Keep it isolated to the component. The scss/css can't bleed outside and can't bleed inside the component from the parent. You can add @import of scss with variables that can be managed from the outside or via props if you need to but the component's style is locked. Just my 2 cents. I like the css module idea but it's not as simple as using scoped.

@LuXDAmore
Copy link

I haven't tested it, but I believe attribute selectors are some of the slowest around.

Didn't this stop being a real problem ages ago? Performance is certainly important, but I'd like to see some actual data to back up that claim.

@casey6 IDK, but maybe here: CSS selector performance

Hope this helps

@aleksei-a-savitski
Copy link

  1. Something that could help to generate critical css and deffer unused css. May be <style critical>. For example, when there is a custom selectbox in above the fold content, we may deffer styles for the selectbox dropdown.
  2. Deterministic way to scope styles. UI component libraries don't use scoped styles because random data-... attributes make it impossible to override styles. Allowing to specify fixed prefix (like BEM style) could solve the issue. For example <style scoped prefix="ui-modal">.

@Phunky
Copy link

Phunky commented Nov 9, 2019

For along time I wasn't aware of >>> to apply styles to child components but other than that i've never had any problems with scoped styles, they are one of the best things about SFC.

Global styles seem to be mentioned a lot in previous comments and this kind be handled with custom loaders such as this;

css: {
    sourceMap: true,
    loaderOptions: {
      stylus: {
        use: [
          styleVars({
            brandColor: process.env.VUE_APP_BRAND_HEX
          })
        ],
        import: [
          '~styles/variables/colours.styl',
          '~styles/mixins/colours.styl',
          '~quasar-variables-styl'
        ]
      }
    }
  },

That imports all my helper methods, mixins and whatever I want accessible in every component without me ever having to think about them.

@aarongarciah
Copy link

Scoped by default. It would not be backwards compatible unless there were a configuration flag. I think it is beneficial because I've never had a component that wasn't scoped. I put global styles in an actual CSS file at the top level.

I think scoped by default would make a lot of sense in a component oriented framework like Vue.

@michaeldrotar
Copy link

I seem to be in the minority here but all of these issues seem easily solvable with standard css practices like BEM that have been around for awhile now... theming, scoping, overrides, deep selectors, etc.

I think a global config to choose if scoped or global is the default is perfectly reasonable, but a backward incompatible change to default scoped would be very painful.

@seifsay3d-zz
Copy link

Dynamic Styling:

The <style> is not aware of the component component state, and therefore lots of computed properties are being created to achieve dynamic styling which bloats up the javascript and hurts readability.

I'm aware that vue-styled-components exists and solves this, but it's not really mature enough.

Theming
In several projects, it was required to provide several themes for the same component.

It would be nice if this functionality is supported out of the box without developers having to write custom webpack loaders so that you can do
<style scoped theme="themeA">
<style scoped theme="themeB">

Configurations
Almost all my components require me to import global scss variables and colors, it would be nice if also if a loader is provided out of the box

@Justineo
Copy link
Member

Use class prefixing as a scoping mechanism instead of attributes?
That would remove performance penalty in runtime. Dynamic classes could be implicitly prefixed in runtime.

See vuejs/vue#9801 (comment)

@Dafrok
Copy link

Dafrok commented Nov 11, 2019

I am not sure that if this is within the scope of current discussion: When developers have to touch DOM, inject elements to the component instance by self maintenance, I always hope there's a function could add scope attributes to that element tree easily.

@599316527
Copy link

599316527 commented Nov 11, 2019

Declaring attributes like <style scoped :deep="3"> or <style scoped recursively> to apply styles of current component to its slots automatically rather than adding deep selectors manually.

@BigGress
Copy link

If "css variable" can be easy way to delcare and has scope, penetrate js variable to css variable.It can make css more flexible.

@HerrBertling
Copy link

As we wrote some days ago on Twitter, @yyx990803: Some kind of obfuscation for class names in scoped styles would be great. Reduces the risk of clashes between SFC component class names and global classes.

I‘ve seen global classes introduced by other devs on a project as well as through some third party component which requires its own CSS.

Simple example: .wrapper or .hint used globally and scoped.

I know, BEM etc could mitigate this, but then why use scoped styles at all? 😄

@rico-ocepek
Copy link

@HerrBertling I know as of now this is just an idea (which I like very much) but could you imagine how we would be able to tell the difference between local and global classes inside the template part of our component? So how could Vue tell which classes to obfuscate and which not?

@chriscalo
Copy link
Contributor

chriscalo commented Nov 11, 2019

Building on @alex-lit's comment about binding data values to CSS, I'd love to see a DRY-er, less verbose mechanism for binding Vue instance values to styles.

To accomplish this today without moving the styling fully into the template, we have to repeat ourselves 3 times:

<template>
  <div
    :style="`
      --height: ${height};
      --background: ${background};
      --color: ${color};
      --padding: ${padding};
    `"
  >
    hi
  </div>
</template>

<script>
  export default {
    data() {
      // assume user interactions update these values
      return {
        height: "100px",
        background: "red",
        color: "white",
        padding: "24px",
      };
    },
  };
</script>

<style scoped>
  div {
    height: var(--height);
    background: var(--background);
    color: var(--color);
    padding: var(--padding);
  }
</style>

What if there were some mechanism for referencing Vue instance values from the <style> block directly?

<template>
  <div>
    hi
  </div>
</template>

<script>
  export default {
    data() {
      // assume user interactions update these values
      return {
        height: "100px",
        background: "red",
        color: "white",
        padding: "24px",
      };
    },
  };
</script>

<style scoped>
  div {
    /* --v-* values are reactively bound to the Vue instance */
    height: var(--v-height);
    background: var(--v-background);
    color: var(--v-color);
    padding: var(--v-padding);
  }
</style>

One powerful solution to this might be an emotion integration that lets me write styles in a <style> block but allows me to embed JS expressions that are interpreted in the context of the Vue instance:

<template>
  <div>
    <span>hi</span>
  </div>
</template>

<script>
  export default {
    data() {
      // assume user interactions update these values
      return {
        height: "100px",
        background: "red",
        color: "white",
        padding: "24px",
      };
    },
  };
</script>

<style scoped lang="emotion">
  /* declarations not in a CSS rule get applied to component's root element */
  height: ${height};
  background: ${background};
  padding: ${padding};
  
  &:hover {
    background: black;
  }
  
  span {
    color: ${color};
  }
</style>

@cristijora
Copy link

cristijora commented Nov 12, 2019

Scoped Related

  • Deep styling is somewhat inconsistent. We have the >>> combinator which unfortunately is not available in sass and also gives warnings in the browser. We also have deep to ::v-deep when using different sass compilers. Having something unified for this would be great.
  • Remove unused css by default. When there are scoped styles (at least without deep selectors), I believe it's rather straight forward to detect the unused css and remove it. Svelte already does this.

Style Block related

  • As mentioned above, binding css variables between style, data and template would be something amazing.
  • Theming as mentioned above. <style theme="themeA">

@CyberAP
Copy link
Contributor

CyberAP commented Nov 13, 2019

I really like the idea of controlled scope.

<style src="./MyButton.css" scope="foo" />

That way you'll have an option to reuse these styles outside of Vue.

@Justineo
Copy link
Member

Justineo commented Nov 14, 2019

The discussion seems to be a bit off the track. The “scoped mechanism” and “sharing variables between script/style” are separate topics. I suggest we discuss the latter one in another issue.

@rickyruiz
Copy link

rickyruiz commented Nov 14, 2019

@chriscalo You could create a custom directive or an utility function for a DRY-er solution.

https://codepen.io/rickyruiz/pen/PooyWNr

<template>
  <!-- <div v-css-variables="$data"> -->
  <div
    :style="computedStyle"
  >
    hi
  </div>
</template>

<script>
  export default {
    data() {
      // assume user interactions update these values
      return {
        height: "100px",
        background: "red",
        color: "white",
        padding: "24px",
      };
    },
    computed: {
      computedStyle() {
        // Can extract function to utils or a directive
        return Object.entries(this.$data).reduce((style, [key, value]) => {
          style[`--${key}`] = value;
          return style;
        }, {});
      },
   },
  };
</script>

<style scoped>
  div {
    height: var(--height);
    background: var(--background);
    color: var(--color);
    padding: var(--padding);
  }
</style>

Using a directive would require using something like this for each property:

export function setCssVar(
  element: HTMLElement,
  propertyName: string,
  value: string | null,
  priority?: string | null
): void {
  return element.style.setProperty(`--${propertyName}`, value, priority)
}

@RomainLanz
Copy link

Should we create another issue/rfc about JS-in-CSS (😄) ideas?

This is one thing that I miss when using .vue file, we cannot have dynamic styling in the <style> tag.

@mesqueeb
Copy link
Contributor

The overlapping styles problem

The biggest issue I have with vue2 scoped styling is that it's not fool-proof.

What I mean is that, (since I'm a fool) I had to learn the hard way that this will break the scoped feature:

Parent component:

<template>
  <div class="wrapper">
    <child-component class="inner" />
  </div>
</template>

Child component:

<template>
  <div class="child-wrapper">
    <div class="inner">an inner div yo!</div>
  </div>
</template>
<style scoped>
.inner {
  background: black
}
</style>

In this case, I'd expect the child to only have its inner div to become black.
However, because the parent has also applied the inner style to the top level of the child component, that child component's scoped styling is now also applied to the whole element.

This is all well if you can just look what scoped classes the child uses, but what if the child component is a plugin, it's way less evident to do this.

I'd love this problem to be fixed. 😉

@ahtee
Copy link

ahtee commented Nov 30, 2019

There's a lot asking about dynamic css styling, and I was just thinking: Maybe this issue can be fixed by declaring that .vue files just wont have this functionality, since the CSS in .vue components is just CSS (or what it seems).

Maybe we need more documentation on creating .js components in the future for this use case on dynamic styles?

Back on the topic:
In .vue components, <style scoped> I will always assume that adding scoped will only add the CSS to that specific component. The slotted component probably shouldn't inherit from the parent component and that slotted component should have its own scoped styles, speaking in a general sense.

If I wanted to add a global style, I will not add scoped and it will be globally available on render and should be loaded on initial render, as it does now.

Just thinking out loud :)

@smhmd
Copy link

smhmd commented Dec 7, 2019

@chriscalo

<style scoped lang="emotion">
  height: ${height};
  background: ${background};
  padding: ${padding};
  
  &:hover {
    background: black;
  }
  
  span {
    color: ${color};
  }
</style>

That looks neat, but it also should integrate with postCSS, CSS preporcessors. People will also be tempted to interpolate CSS properties (e.g, change padding-left to padding-right when the direction of writing changes), how would autoprefixer, for instance, work on dynamically constructed CSS? maybe, it's a solved issue.

@cawa-93
Copy link

cawa-93 commented Dec 24, 2019

Scoped styles cause problems when working with third-party component libraries such as vuetify.

For example: I have a component that contains a third party component

<template>
  <p>
    some lorem text
    <v-btn>My button</v-btn>
  </p>
<template>

Now i need change some styles in <v-btn> component.

<style scoped>
.v-btn__content {
   /* some styles ... */
}

If you are faced with this situation you know that it will not work. Isolated styles do not apply to the nested component.

To work around this problem, I have to implement my own namespace using preprocessors.
First component root element must have unique class name.

<template>
  <p class="my-component-name">
    some lorem text
    <v-btn>My button</v-btn>
  </p>
<template>

Then remove scoped attribute and wrap all styles in to .my-component-name selector

<style lang="scss">
.my-component-name {
  .v-btn__content {
    /* some styles ... */
  }
}

Why not do something like this right out of the box?

Instead of generating and placing a bunch of unique attributes, just create one unique class name and add it to all selectors?

<template>
  <p>
    <button>Button</button>
  </p>
</template>

<style scoped>
  button {
    font-size: 16px;
  }
</style>

Compiled to:

<p class="component-name">
  <button>Button</button>
</p>
  
<style>
  .component-name button {
    font-size: 16px;
  }
</style>
  • So the output we get: a cleaner css code.
  • All styles are in an isolated environment and do not go beyond the component.
  • It is possible to apply styles to nested components.

@rico-ocepek
Copy link

rico-ocepek commented Dec 24, 2019

@cawa-93 that's exactly where the deep selector comes in handy:
https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors

That's just regarding your Initial problem and shouldn't mean your proposal isn't worth consideration.

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