Skip to content

Scoped styles don't apply to v-html injections #749

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

Closed
foundryspatial-duncan opened this issue Mar 28, 2017 · 20 comments
Closed

Scoped styles don't apply to v-html injections #749

foundryspatial-duncan opened this issue Mar 28, 2017 · 20 comments

Comments

@foundryspatial-duncan
Copy link

foundryspatial-duncan commented Mar 28, 2017

Version

11.0.0

Reproduction link

https://github.com/foundryspatial-duncan/vue-loader-issue-demo/blob/master/src/App.vue

Steps to reproduce

  1. In a single-file Vue component (.vue file), add some scoped styles (with the scoped property on the style tag).
  2. Inject some HTML that matches your scoped style's selector with v-html

What is expected?

The styles would affect the injected HTML

What is actually happening?

The styles do not affect the injected HTML


Looks like HTML injected with v-html aren't given the "data-v-[hash]" property (like data-v-08ce5946).
I think there's a proposal somewhere to only add the data-v-[hash] to the component's root element and then prefix all the styles to scope them. That would solve this issue as well.

@yyx990803
Copy link
Member

Prefixing is simply different from what scoped CSS does. The HTML injected is raw and we are likely not going to change this. You can just give the container element a class and use nested selectors to style the raw HTML.

@Xheldon
Copy link

Xheldon commented Apr 21, 2017

There still has a problem.
some info:

"dependencies": {
"vue": "^2.2.4",
"vue-highlightjs": "^1.2.2",
"vue-markdown": "^2.1.3"
},
"devDependencies": {
"autoprefixer": "^6.7.7",
"babel-cli": "^6.24.0",
"babel-eslint": "^7.2.1",
"babel-loader": "^6.4.1",
"babel-plugin-component": "^0.9.1",
"babel-plugin-dynamic-import-node": "^1.0.1",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.24.0",
"babel-preset-stage-2": "^6.22.0",
"css-loader": "^0.28.0",
"eslint": "^3.19.0",
"eslint-config-standard": "^10.0.0",
"eslint-loader": "^1.7.1",
"eslint-plugin-html": "^2.0.1",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-node": "^4.2.2",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^2.3.1",
"eventsource-polyfill": "^0.9.6",
"express": "^4.15.2",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.11.1",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.28.0",
"ip": "^1.1.5",
"node-sass": "^4.5.2",
"ora": "^1.2.0",
"progress-bar-webpack-plugin": "^1.9.3",
"sass-loader": "^6.0.3",
"url-loader": "^0.5.8",
"vue-loader": "^11.3.4",
"vue-router": "^2.4.0",
"vue-style-loader": "^2.0.5",
"vue-template-compiler": "^2.2.6",
"webpack": "^2.3.1",
"webpack-dev-middleware": "^1.10.1",
"webpack-hot-middleware": "^2.18.0",
"webpack-merge": "^4.1.0"
}

template:

<span class="focus-btn" @click="focus" :class="{'focued': isFocus}" v-html="isFocusText"></span>

script:

computed: { isFocusText () { return this.isFocus ? '已关注' : '<i class="plus">+</i>关注'; } }

scss:

<style scoped lang="scss"> .focus-btn i.plus{ color:red;} </style>

Omit some unrelated code.

it's style not work till remove 'scope' in style tag.

Should I remove 'scope' in style tag or remove '<i>' in isFocusText?

Whether I style element in raw html?

@foundryspatial-duncan
Copy link
Author

You could use something like v-if to show your focus text instead. @yyx990803 said above that they probably won't address this, but if you're using scss you can "scope" your styles by nesting everything in a selector for your component's root element. So, not the end of the world 👍

@MikaelEdebro
Copy link

You can use the /deep/ selector to get your styles to be applied:

<div class="description" v-if="description" v-html="description"></div>

.description {
  /deep/ p {
    margin-bottom: 10px;
  }
}

@nsfmedina
Copy link

/deep/ selection helped me a lot. Thanks :)

@alancwoo
Copy link

alancwoo commented Aug 27, 2018

I stumbled upon this today and oddly, nothing was working (unscoped css, global css).

I noticed that while this solution worked, the /deep/ selector was deprecated by some time ago and throws errors in IE: https://stackoverflow.com/questions/25609678/what-do-deep-and-shadow-mean-in-a-css-selector

I then found this: https://medium.com/@brockreece/scoped-styles-with-v-html-c0f6d2dc5d8e

Which recommends something along the lines of:

.description >>> p {
  margin-bottom: 10px;
}

Which works as well, without a deprecated selector.

edit: Then again, the vue docs say >>> is just an alias for /deep/, so I'm not sure anymore https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors

@foundryspatial-duncan
Copy link
Author

Since the discussion is still going on, I just wanted to draw attention to my comment above about using the root element's selector to scope your styles. It can produce simpler, more predictable style behaviors and doesn't muddy up the DOM with the extra scope attributes. You just have to be aware of how one component's styles might affect its child components. I use the scoped attribute pretty sparingly these days, in favor of a slightly more thoughtful design. I think it's worth considering if it suits your project!

@alancwoo
Copy link

Yes I totally agree - something very weird was happening where even unscoped Styling in the component and even the global Stylesheet was not working - and only the deep selector worked - in the end it turned out webpack was hung up on something and restarting it fixed everything.

I agree I would aim for a root selector instead as well and switched things over when it worked again.

@renesansz
Copy link

renesansz commented Oct 10, 2018

You can use the /deep/ selector to get your styles to be applied:

<div class="description" v-if="description" v-html="description"></div>

.description {
  /deep/ p {
    margin-bottom: 10px;
  }
}

wow! /deep/ works. learned something today :)

@N8mare
Copy link

N8mare commented Nov 27, 2018

I am using <style lang="scss" module> and I am passing a raw html from my backend config. footer: 'some text \n'+ '<a href="#" :class="$style.tc">link</a>',
In the original component:
<div :class="$style.footer"> <p :class="$style['footer-text']" v-html="footer"></p> </div>


.footer-text{ /deep/ a{ color: #1665c0; text-decoration: none; } }
The above style is applied to the link element and it works fine. But when I replace 'a' with '.tc'(class name) it does not work.
.footer-text{ /deep/ .tc{ color: #1665c0; text-decoration: none; } }
Also the alias for '/deep/' ,i.e, '>>>' does not work

@RahulDey12
Copy link

/deep/ p

not working with with scss

@carlosabcs
Copy link

/deep/ p

not working with with scss

In my case, with scss, it is working pretty fine:

    /deep/ &-icon {
      // See: https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors
      font-size: 30px;
    }

@ZermattChris
Copy link

Not sure if I missed it, but would be great to put a mention in the Docs about this not working (might save some churn for other noobs like myself :-) )

@luquera
Copy link

luquera commented Dec 8, 2020

You can use the /deep/ selector to get your styles to be applied:

<div class="description" v-if="description" v-html="description"></div>

.description {
  /deep/ p {
    margin-bottom: 10px;
  }
}

/deep/ works bro, tks so much

@gblue1223
Copy link

/deep/ is not working in Vue@2.6.12 use ::v-deep instead.
.right { ::v-deep * { ... } }

@ayoubkhan558-zz
Copy link

ayoubkhan558-zz commented May 23, 2021

Try this :)

<div class="content" v-html="content"></div>
.content ::v-deep {
  h2 {
    color: blue;
  }
  a {
    color: blue;
  }
}

@chaderenyore
Copy link

I stumbled upon this today and oddly, nothing was working (unscoped css, global css).

I noticed that while this solution worked, the /deep/ selector was deprecated by some time ago and throws errors in IE: https://stackoverflow.com/questions/25609678/what-do-deep-and-shadow-mean-in-a-css-selector

I then found this: https://medium.com/@brockreece/scoped-styles-with-v-html-c0f6d2dc5d8e

Which recommends something along the lines of:

.description >>> p {
  margin-bottom: 10px;
}

Which works as well, without a deprecated selector.

edit: Then again, the vue docs say >>> is just an alias for /deep/, so I'm not sure anymore https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors

Any one still having this issue sould use this comment and not deep because as the user said it is deprecated. thanks a lot

@chaderenyore
Copy link

Update!!!!!!!!
As of March 2022 the /deep/ and >>> deep selectors have been deprecated.
Now you should use :deep()

.a :deep(p) {}
to go deeper and target the p tag

@beatrizsmerino
Copy link

beatrizsmerino commented Mar 30, 2022

How do I use /deep/ or >>> or ::v-deep in Vue.js?

To add styles to child components from the parent component...

In Vue 2:

  • The /deep/ syntax is deprecated
  • Use ::v-deep with Sass, use >>> without Sass
<style scoped>
    .parent-component {
        ::v-deep {
            .child-component {
                background-color: #000000;

                p {
                    color: #ffffff;
                }
            }
        }
    }
</style>

In Vue 3:

  • ::v-deep .child-class is deprecated in favor of :deep(.child-class)
  • The ::v- prefix is deprecated in favor of :
  • The >>> syntax is deprecated
  • The /deep/ syntax is deprecated
<style scoped>
    .parent-component {
        :deep {
            (.child-component) {
                background-color: #000000;

                p {
                    color: #ffffff;
                }
            }
        }
    }
</style>

Also in Vue 3 you can use 2 new selectors:

  • To register global styles even from a scoped component you can use the:global(.my-class) selector.
  • For access to <slot> element you can use :slotted(.child-class) selector.
<style scoped>
    .parent-component {
        :global {
            p {
                color: #000000;
            }

            (.my-class) {
                background-color: #000000;

                p {
                    color: #ffffff;
                }
            }
        }

        :slotted {
            (.slot-child-component) {
                background-color: #000000;

                p {
                    color: #ffffff;
                }
            }
        }
    }
</style>

@leegee
Copy link

leegee commented May 13, 2022

Would it be a good idea to add this to the documentation?

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