Vue.js 2: Scoped style not working with sass/scss - vue.js

In my Vue.js component when I set the style to "scoped", the styles are ignored:
<style lang="sass" scoped>
I get the following error in the console:
[HMR] unexpected require(609) to disposed module
It's working as expected if I don't add the "scoped" attribute.

Converting my comment to an answer.
When you work with scoped style(s) Vue adds data attribute with an unique value to all tags in your component and then silently modifies your CSS/SASS selectors to rely on this data attribute.
For example, .list-container:hover becomes .list-container[data-v-21e5b78]:hover
If you need a deep selector - that is, which affects child components - you can use a combinator
<style scoped>
.a >>> .b { /* ... */ }
</style>
which will be compiled into
.a[data-v-f3f3eg9] .b { /* ... */ }
If SASS is unable to parse the >>> combinator you can replace it with /deep/ instead.
If you do not use the combinator then
<style scoped>
.a > .b { /* ... */ }
</style>
would be compiled into
.a > .b[data-v-f3f3eg9] { /* ... */ }

You can use the ::v-deep combinator to target scoped styles of a child component.
Example:
<template>
<main class="content">
<child-component></child-component>
</main>
</template>
In this case, if you wanted to change the color of paragraphs <p> in the child component, you could do what with:
.content ::v-deep p {
color: red;
}

Related

Undefined mixin sass

I get error undefined mixin when i use #include in components
I work in NuxtJs, install sass-loader, node-sass
Component
<style lang="scss">
.cardSmall {
#include mq(laptop) {
width: 720px;
}
}
</style>
My mixin in assets/variables.scss
#mixin mq($breakpoint) {
#if $breakpoint==laptop {
#media only screen and (max-width: 991px) {
#content
};
}
}
Nuxt imports several things automatically such as components and composables. But it doesn't auto-import (sass) mixins. Therefore you need to add an import to the top of your <style /> tag:
<style lang="scss">
#use "#/assets/variables.scss";
// ...
</style>

How to apply a body {} style to specific vue component

I'm using scoped style for most of my components to not interfere with other components.
Some of my views/components need body { overflow: hidden; }, but others don't.
I can't use
<style scoped>
body {
overflow: hidden;
}
...
</style>
How can i apply this style when specific components are loaded? (i am using vue router if that helps)
You may send a prop to your component like described in here: https://v2.vuejs.org/v2/guide/components-props.html
Let's call you prop isOverflowHidden, and create .hidden class in your css.
After that, you can add your wrapper element (first tag in component) :class="{ hidden: isOverflowHidden }"
Or you can move it to a method.
If you want you can use this this action for inline-styling.
<div :style="{ overflow: (isOverflowHidden ? 'hidden' : '')}"></div>
You can read extended information in here: https://v2.vuejs.org/v2/guide/class-and-style.html#Binding-Inline-Styles

How to use deep selector in scss in vue

How to use deep selector in scss in vue?
The code below not work.
<style lang="scss" scoped>
.a{
&>>>.b{
...
}
}
</style>
A deep selector like >>> in css but in scss inside vue single file component.
I had the same issue, and i eventually fix this using ::v-deep as stated here:
https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors
<style lang="scss" scoped>
.v-input {
::v-deep .v-text-field__details {
min-height: 0;
margin: 0;
.v-messages {
min-height: 0;
}
}
}
</style>
From the vue docs:
"Some pre-processors, such as Sass, may not be able to parse >>> properly. In those cases you can use the /deep/ combinator instead - it's an alias for >>> and works exactly the same."
So try this:
<style lang="scss" scoped>
.a {
/deep/ .b {
...
}
}
</style>

Conditionally override css in Style tag

Assuming I am using a plugin that generates html at runtime where I cannot edit the CSS or JS code, leaving me with the only option of overriding certain CSS in particular classes. For instance, in such case I'd often do:
.video-player{
max-height: 500px !important;
}
In case such styling must be handled conditionally based on the props passes to the component, for instance:
<videoPlayer :goSmall="anotherColumn != null"></videoPlayer>
since the CSS in the videoPlayer components must go in the Style tag:
<style scoped>
.video-player{
max-height: 500px !important;
}
</style>
how can I render it conditionally?
It is such a bad idea to append it to the DOM using lifecyle hooks, so please do not suggest anything like that.
Why not apply a specific class to the component instead of passing a prop?
<videoPlayer :class="{ small: anotherColumn != null }"></videoPlayer>
And the css
<style scoped>
.video-player.small {
max-height: 500px !important;
}
</style>
If you are not okay with dynamically applying CSS using lifecycle hooks. You can always box your components. Make two components for your videoPlayer, we'll call them videoPlayerOriginal and videoPlayerSmall.
//videoPlayerOriginal.vue
<videoPlayer></videoPlayer>
Add your css in videoPlayerSmall.vue
//videoPlayerOriginal.vue
<videoPlayer></videoPlayer>
<style scoped>
.video-player{
max-height: 500px !important;
}
</style>
Now render either one of them conditionally.

Vue.js style v-html with scoped css

How can I style v-html content with scoped css using vue-loader?
Simple example:
component.vue
<template>
<div class="icon" v-html="icon"></icon>
</template>
<script>
export default {
data () {
return {icon: '<svg>...</svg>'}
}
}
</script>
<style scoped>
.icon svg {
fill: red;
}
</style>
generate html
<div data-v-9b8ff292="" class="icon"><svg>...</svg></div>
generate css
.info svg[data-v-9b8ff292] { fill: red; }
As you can see v-html content don't have data-v attribute, but generate css have data-v attribute for svg.
I know this is expected behavior for vue-loader (https://github.com/vuejs/vue-loader/issues/359). And in this issue descendent selectors mentioned. But as you can see I use it in my css and it's not worked.
How can I style v-html content?
I am using vue-loader 15.9.1. The >>> solution did not work for me (no effect) whereas the /deep/method resulted in building errors...
Here is what worked instead:
.foo ::v-deep .bar { color: red; }
As stated in my answer here:
New version of vue-loader (from version 12.2.0) allows you to use "deep scoped" css. You need to use it that way:
<style scoped> now support "deep" selectors that can affect child
components using the >>> combinator:
.foo >>> .bar { color: red; } will be compiled into:
.foo[data-v-xxxxxxx] .bar { color: red; }
More informations on the release page of vue-loader
AS Sarumanatee said if the accepted answer doesn't work try:
.foo /deep/ .bar { color: red; }
Using /deep/ selector with SCSS didn't work for me but then I tried using ::v-deep selector
e.g
::v-deep a {
color: red;
}
See this answer