vuejs / rfcs

RFCs for substantial changes / feature additions to Vue core
4.87k stars 548 forks source link

SFC scoped style improvements #94

Open yyx990803 opened 4 years ago

yyx990803 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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:

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 commented 4 years ago

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 commented 4 years ago

A few things I have in mind:

hecktarzuli commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

:boom: 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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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