19

I'm trying to use Bootstrap in a Vue component, and I want all CSS to be scoped. I tried something like this:

<style scoped>
@import "~bootstrap/dist/css/bootstrap.css";
@import "~bootstrap-vue/dist/bootstrap-vue.css";
</style>

But it doesn't seem like the css is scoped. Is there any way to do that?

vitalii
  • 201
  • 1
  • 2
  • 3

5 Answers5

38
<style scoped src="~bootstrap/dist/css/bootstrap.css"></style>

<style scoped src="~bootstrap-vue/dist/bootstrap-vue.css"></style>

Update: a hack using SCSS

Reason why the first solution won't work:

With scoped, the parent component's styles will not leak into child components.

If you want a selector in scoped styles to be "deep", i.e. affecting child components, you can use the >>> combinator

from the Vue doc for scoped CSS

The modal you mentioned is apparently not being controlled by the component where you imported bootstrap. Perhaps it's a child component. Perhaps you're using the jquery version of Bootstrap modal. Either way, the data attributes won't be added to the modal.

In order to solve this, you need Deep Selector. (you may read about it in more detail in https://vue-loader.vuejs.org/en/features/scoped-css.html)

Here's how I would import the entire Bootstrap CSS using SCSS. (I think it's impossible to do this using pure CSS only.)

<template>
  <div class="main-wrapper">
    /* ... */
  </div>
</template>

<style scoped lang="scss">
.main-wrapper /deep/ {
  @import "~bootstrap/dist/css/bootstrap.min";
}
</style>

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.

The generated CSS would be similar to

.main-wrapper[data-v-656039f0] .modal {
    /* some css... */
}

.. which is what you want.

BUT, I gotta say, importing the entire Bootstrap CSS is a really bad practice. Try to import only and exactly what you are going to use from bootstrap-sass instead.

This solution is hacky. But it's the only way I know that can work for your use case.

Jacob Goh
  • 19,800
  • 5
  • 53
  • 73
  • It does the job, but it's not OK in case of Bootstrap - dynamically generated elements don't seem to have the attributes. I tried that on simple modal and it doesn't seem to work. – vitalii Apr 04 '18 at 15:01
  • Should add more info and explanation to this problem. – Eka Apr 04 '18 at 15:31
  • 1
    am trying to update. give me a few more minutes @Eka – Jacob Goh Apr 04 '18 at 15:32
  • the @import cant be scoped, its always applied globally – ctf0 Aug 04 '18 at 05:21
  • @ctf0 it's not a css import. It's a scss import – Jacob Goh Aug 04 '18 at 05:26
  • yes i understand thats why we didnt use the `url()` for import, however on compiling vue will convert it as a normal css import and you will get a style with @import in ur header – ctf0 Aug 04 '18 at 05:39
  • @ctf0 apparently if it’s converted to a css import, there's something wrong with the way you use it in scss. – Jacob Goh Aug 04 '18 at 05:51
  • isnt `@import "~bootstrap/dist/css/bootstrap.min";` going to import the css file ? – ctf0 Aug 04 '18 at 06:02
  • @ctf0 yes but it's going to import it in a SCSS way. You shouldn't see any `@import ...` in the generated css. (Not sure if I understood your problem coorrectly) – Jacob Goh Aug 04 '18 at 06:40
  • Works great. The only minor problem was with [Modal component](https://bootstrap-vue.js.org/docs/components/modal) which (logically) must have `static` attribute to render inside its parent component. – Radek Svítil Dec 02 '19 at 09:13
  • IMPORTANT note re. above... If like me you try to @import a .css file, it won't work (will be applied globally). Rename your .css file to .scss then it will work – LMK Feb 24 '21 at 21:08
  • 1
    @LMK you don't need to rename the extension, just import it WITHOUT the extension like in the answer. `@import "~bootstrap/dist/css/bootstrap.min";` – Jacob Goh Feb 25 '21 at 01:20
6

I know it's an old question but this solution work for me

<style lang="scss" scoped>
 ::v-deep {
   @import 'bootstrap/scss/bootstrap.scss';
 }
</style>
4

i wanted use vuetify in my app only on a page , and that crashed my css, then I use

 <style scoped src="vuetify/dist/vuetify.min.css"></style>

and now all works perfectly .


<template>
  <div> .......  </div>
</template>

<style scoped src="vuetify/dist/vuetify.min.css"></style>
<script> ...... </script>
Ing Oscar MR
  • 769
  • 7
  • 7
0

For me this was the solution to get it to work and prevent leaking:

<style lang="less" scoped>
    ::v-deep {
        @import (less) "../node_modules/vuetify/dist/vuetify.min.css";
    }
</style>

The casting to less could obviously also be changed to scss.

ill
  • 352
  • 2
  • 4
  • 23
0

They changed the ::v-deep selector in Vue 3, the old method still works, but is deprecated (which can lead to a lot of deprecation messages in your build if you're importing css/scss in this way).

So for the record, this is how you would go about it in Vue 3:

<template>
    <div class="main-wrapper">
        <div class="bootstrap-scope">
            /* All children that need Bootstrap including slotted content etc */
        </div>
    </div>
    
</template>

<style scoped lang="scss">
    .main-wrapper::v-deep(.bootstrap-scope) {
        @import "~bootstrap";
    }
</style>

You can also drop the div.main-wrapper and select the root div SFC component. Lets say your component name is my-awesome-component the selector would be:

<style scoped lang="scss">
    .my-awesome-component::v-deep(.bootstrap-scope) {
        @import "~bootstrap";
    }
</style>

Or if you prefer not to use a generated class name you can also go for:

<style scoped lang="scss">
    div:first-child::v-deep(.bootstrap-scope) {
        @import "~bootstrap";
    }
</style>

In actual shadowDom you would use the :host selector to select the root of your component which would make this a more concise, but from what I understand (https://github.com/vuejs/vue-loader/issues/1601) the vue-loader team didn't decide yet what to do with this.

The :deep() selector has a small section devoted to it in the official Vue 3 docs: https://v3.vuejs.org/api/sfc-style.html#deep-selectors

There's also a VueJS RFCS on the deep selector which describes in more detail why it keeps on changing: https://github.com/vuejs/rfcs/blob/master/active-rfcs/0023-scoped-styles-changes.md

Thomas
  • 550
  • 3
  • 11