-
Notifications
You must be signed in to change notification settings - Fork 546
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
Comments
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 |
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. |
This is interesting.. I've never used I thought this was the intended usage given this note: Scoped styles do not eliminate the need for classes. |
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. |
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 |
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. |
Coming from an Angular background, a thing I really miss in Vue SFC is the |
A few things I have in mind:
|
@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. |
@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. |
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 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.
|
💥 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. |
You can do things like this: <div style="--some-color: blue"></div> div {
color: var(--some-color, 'red');
} Replace style with a Personally I think it's alot easier to not used More info: |
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. |
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:
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 You have global selectors like |
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. |
Use class prefixing as a scoping mechanism instead of attributes? Also render functions are left out of this feature, maybe something could be improved in that regard? |
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 |
I’d like to see a way to use dynamic styles other than relying on a predefined 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. |
Please tell (in documentation) about the |
@alex-lit It's in the vue-loader docs |
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> |
Deterministic scoped selectors values would be great, maybe even a way to define how the This comes in handy when you have multiple webpack jobs that should produce compatible style / components. |
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. |
|
@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. eg. https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors |
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. |
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. |
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 🤔 |
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. |
@casey6 IDK, but maybe here: CSS selector performance Hope this helps |
|
For along time I wasn't aware of Global styles seem to be mentioned a lot in previous comments and this kind be handled with custom loaders such as this;
That imports all my helper methods, mixins and whatever I want accessible in every component without me ever having to think about them. |
I think scoped by default would make a lot of sense in a component oriented framework like Vue. |
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. |
Dynamic Styling: The I'm aware that vue-styled-components exists and solves this, but it's not really mature enough. Theming 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 Configurations |
|
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. |
Declaring attributes like |
If "css variable" can be easy way to delcare and has scope, penetrate js variable to css variable.It can make css more flexible. |
As we wrote some days ago on Twitter, @yyx990803: Some kind of obfuscation for class names in 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: I know, BEM etc could mitigate this, but then why use scoped styles at all? 😄 |
@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? |
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 <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 <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> |
Scoped Related
Style Block related
|
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. |
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. |
@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)
} |
Should we create another issue/rfc about JS-in-CSS (😄) ideas? This is one thing that I miss when using |
The overlapping styles problemThe 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 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. 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. 😉 |
There's a lot asking about dynamic css styling, and I was just thinking: Maybe this issue can be fixed by declaring that Maybe we need more documentation on creating Back on the topic: If I wanted to add a global style, I will not add Just thinking out loud :) |
That looks neat, but it also should integrate with postCSS, CSS preporcessors. People will also be tempted to interpolate CSS properties (e.g, change |
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 <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. <template>
<p class="my-component-name">
some lorem text
<v-btn>My button</v-btn>
</p>
<template> Then remove <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>
|
@cawa-93 that's exactly where the deep selector comes in handy: That's just regarding your Initial problem and shouldn't mean your proposal isn't worth consideration. |
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).The text was updated successfully, but these errors were encountered: