Scope Bootstrap Css in Vue - css

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?

<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.

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>

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>

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.

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

Related

Vue Vite scoped css won't assign style

I'm trying to add a background-image to a view in vue vite. I don
't want to set this background-image on every view so I tried to add it inside the views site using a scoped css style.
But once I assign scoped to the style tag it won't use the style...
Example code which doesn't work:
<style lang="css" scoped>
body{
background: url("../../assets/images/background.jpg") !important;
}
</style>
Once I remove the scoped it would work but it would add the background to every view which shouldn't happen. Does anyone know why this happens?
From the docs
When a <style> has the scoped attribute, its CSS will apply to elements of the current component only.
This means thst only the elements in your <template> will get the style and since there is no <body> in your template, then it doesn't get style.

vue / nuxt - import CSS from API and insert it in component

I want to insert into component inline css like
<div id="slide1" :style="item.css" v-html="item.html" />
Where my item.css contains string with many css definitions e.g.
#slide1 {} #slide1 p {} #slide1 h2 {} #media(...) { #slide {} } ....
What is the best approach to do this?
So what you are doing here is not loading styles, you are loading a full css set of rules. The style property of an HTML element will only let you add css properties, not blocks of rules like #slide1 {...}.
If you want to load the rules for a singular component remotely, you will want to do use a scoped style block for your component (assuming you are using single file components), like so:
<template>
...
</template>
<style scoped>
#import url("link-to-your-remote-styles");
</style>
What we're doing above is:
making sure that the styles loaded in this component will not bleed out of its scope by using the scoped attribute of the <style> tag;
loading the styles using the #import rule from CSS
Here's a link to a sandbox where I load tailwind just for the scope of one component.

Can i apply an external css file only to a div and its children?

I don't think it is possible, but I will ask anyway:
Can I apply an external css file (Bootstrap for instance) to a div and its children without affecting the rest of the page.
For example, I need to migrate a footer written with Bootstrap over to an existing page. That page does not use bootstrap. If I link Bootstraps css at the top of the page, the css is applied to the whole page which ruins existing css. How can I just apply the bootstrap styles to the footer section without having to rewrite most of the page's css?
Any suggestions?
I ended up using LESS to compile a new css of bootstrap with a prefix of .bootstrap as seen below. It works, but i wonder if there is a more traditional way of handling this problem.
file: bootstrap-only.less
.bootstrap {
#import 'bootstrap.css'
}
file: bootstrap-only.css
.bootstrap .container {
width: 100%;
}
file: page.html
<style>
.container { width: 20px; }
</style>
<link rel="stylesheet" type="text/css" href="bootstrap-only.css">
<div class="not-bootstrap">
<div class="container">I am 20px</div>
</div>
<div class="bootstrap">
<div class="container">I am 100%</div>
</div>
You can try usig scooped css.Please do refer the following sample code.
<div>
<style scoped>
#import "filename.css";
</style>
//your div with its children will come here
</div>
Your inline styles should not be affected by adding Bootstrap as inline styles take precedence over styles from external resources. The only elements that should be affected are the ones in the page that share class names with bootstrap classes.
You can try referencing the Bootstrap css before your own css and your stylesheet will take precedence over the Bootstrap css. Unfortunately this may add styles additional styles to some of your classes which that you didn't explicitly reference in your stylesheet and may still change the look of your page.
For those classes that exist in both bootstrap and your stylesheet it's probably best to just change the names of those classes in your stylesheet and page. A quick way to do this is to use "replace" search for the class name and replace it with the new class name most IDEs have a way to "replace all" so it's often just a bit of typing and a few clicks to change a bunch of styles.
You can try using the Angular 2+, where you can simply create an component and us it anywhere irrespective of the page css. Basically it will create a shadow DOM and will not be accessible outside that component.

Sharing common CSS across VueJS components

I'm working on the VueJS 2 project and I'm trying to clean the code but struggle with scoped styling.
Here is my requirements. :)
I have 3 components those are very similar to each others, so I decide to use mixins to merge the code into one file. Each component will use that mixins of both template and vuejs. When I want to customize the conditions of a particular component, I can simply override the code in it and it is working fine in this part.
However, one thing that I want to do more is to move the scoped style to the mixins as well. At the moment, the style is wrapped in <style lang="scss" scoped></style> tag and this style works very well on its component but I have to duplicate the styling codes into all 3 components.
I know I can add these styles to the global css file but I don't want some styles to the global scope, only one these 3 components will apply for these.
Is it any way to add these styles and apply to mixins?
What is the best practice to code this particular case?
Vue makes this easy.
Solution
To use shared styles in a component you can do this.
MyComponent.js
<template>
</template>
<script>
</script>
<style lang="scss" scoped>
#import '#/scss/shared-styles.scss';
#import 'styles.scss'; // this is the regular CSS used just by the component
</style>
Alternative
You can also import the shared CSS files in the component CSS file instead like below.
MyComponent.js
<template>
</template>
<script>
</script>
<style lang="scss" scoped>
#import 'styles.scss';
</style>
styles.scss
#import '#/scss/shared-styles.scss'
// rest of your component CSS
Automatically import global styles
If you want certain styles to be available in ALL your components you can do this.
vue.config.js
module.exports = {
...
css: {
loaderOptions: {
sass: {
prependData: `
#import "#/scss/global.scss";
`
},
},
},
}
I just found out the scoped style also affect on the child components as well.
Therefore, I found the solution, not sure is it the best practice but I feel very nice for it.
Create a WrapperComponent and I put the scoped style here and a small template.
<template>
<div>
<slot></slot>
</div>
</template>
<style lang="scss" scoped>
/* css style that will apply to all children */
</style>
What happen here is that, when we wrap whatever components with this WrapperComponent, the template will pass on the HTML via slot without any modification and style will be able to apply from now on.
In mixins, I import this wrapper and wrap the component template with the WrapperComponent. Here is the example.
import WrapperComponent from './WrapperComponent'
let MyMixins = {
template: `<wrapper-component>
<div>
Whatever HTML code here
</div>
</wrapper-component>`,
components: {
WrapperComponent,
},
};
When we use this mixins or a child component, the style from WrapperComponent will be automatically applied and also can be used with other groups of components those want to use the same parent style.
Perhaps use modules instead of setting up a style section with a scoped attribute.
https://vue-loader.vuejs.org/en/features/css-modules.html
This way your CSS will still be scoped and not part of your global styling.
I just dropped my fadeTransition.css file into my vue app /assets folder, and import like this:
<template>
<transition name="fade">
<div v-if="showContent">test</div>
</transition>
</template>
<script>
import '#/assets/fadeTransition.css';
// component definition
</script>
fadeTransition.css
/* fade menus in, not out */
.fade-enter-active {
transition: opacity .5s;
}
.fade-enter {
opacity: 0;
}
Clean and simple. Should work for scss, too.
Cheers!

Scoped CSS not being applied within the component

I have the following form component:
<template>
<div>
<form>
<input placeholder="Recipe Name">
<textarea placeholder="Recipe Description..." rows="10"></textarea>
</form>
</div>
</template>
<script>
export default {
name: 'AddRecipeForm'
}
</script>
<style scoped>
form {
display: flex;
flex-direction: column;
}
</style>
The <style> uses the scoped attribute.
When applied, the CSS does not get loaded in. When scoped is removed, it does get applied.
However I want to keep it local to the component.
Why is the CSS not getting applied when the scoped attribute is present?
It appears this was solved by doing a full-reload of the page. Hot reload should take care of scoped css.
However for future viewers, This is commonly asked when scoped CSS isnt being applied to a child component. This can be solved by using deep selectors. (e.g: Using a .selector >>> .desired-selector {})
EDIT: Since this is still getting activity, I'll bring my comment into the answer. ::v-deep also works depending on what preprocessor you're using.
Vue 3 Edit
Now that Vue 3 is stable and been in full release for a while, see the Vue 3 docs for deep selectors: https://vuejs.org/api/sfc-css-features.html#scoped-css
Namely, this syntax is now: :deep(.some-class). There are also some new features which can be read in the linked docs above.
For some reason, scoped styles don't get applied during hot reload when they are first added to the component. Full page reload fixes the issue, from there the styles, since they have been detected, get updated with consecutive hot reloads.
Precisely same symptoms as the OP but none of the recommendations here so far have worked and I need to move on so our solution is to rely on CSS selectors normally:
add a uniquely-named class to the top-level element below <template>
prefix all scoped (non-global) selectors with that uniquely-named class
which had the unexpected but welcome upside when live-debugging our CSS is that the origin of the CSS rule is now obvious in devtools.
MyComponent.vue
<template>
<v-card class="MyComponent" ... >
<div class="fancyBox" ... >
/* ... */
</v-card>
</template>
<style>
.MyComponent .fancyBox { /* scoped to any MyComponent instance */ }
.globalBox { /* we wouldn't put a global style here, obv */ }
</style>
Yes, it's a pain to prefix component-scoped styles this way, but, at least it's a familiar thing to do and you get the added benefit in devtools of tracing the source of a style back to the component that declared it.
Caveat is that, of course, parent-scoped CSS will also bleed down to child-scopes. This, at least, is familiar CSS behaviour.
Rebuilding the Vue App by running 'yarn serve' has fixed the problem for me.

Resources