Bootstrap overrides scoped component styles - css

I have a nuxt project, my project scss structure is that I have a main.scss which is my global scss file for variables and font imports and such.
Primary scss I write inside components under the scoped tag.
My global styles and bootstrap seems to work fine, but when I try to
add scoped styles to my component, they are overwritten by bootstrap.
For example, This is my navbar.vue component:
<style lang="scss" scoped>
nav {
padding: 3rem;
}
</style>
The components bootstrap elements work fine but my added padding is overwritten.
Here is my nuxt.config:
css: [
// '#/assets/scss//bootstrap.css',
'#/assets/scss/main.scss',
],
modules: [
...
'bootstrap-vue/nuxt'
],
bootstrapVue: {
bootstrapCSS: false,
bootstrapVueCSS: false
},
styleResources: {
scss: ['./assets/scss/*.scss']
},
Here is my main.scss:
#import "variables";
#import "fonts";
#import "~bootstrap/scss/bootstrap.scss";
If i remove my bootstrap.scss import I ofcourse lose my bootstrap styling, but the styling I've added in my scoped component works.

As I know the attribute scoped is actual not supported well by browsers. The status of the element is more experimental as I remember. So if you use scoped styles they may be not prioritised over the other stylesheets.
Maybe you may have a look to canIUse.com:
https://caniuse.com/?search=scoped

Related

webpack: scoping all SCSS under vue app selector

I am writing a vue app that renders inside a page on a "traditional" server-rendered site, in this container:
<div id="account-summary-container"></div>
Things work great when developing locally. But when run within the context of the website there is alot of style collision, because both my app and the website's styles are global. My app screws up styles on the entire site.
How can I scope all styles in my app to be local to the selector my app is rendered within?
My app uses bootstrap 4 styles which I am loading with css-loader.
I have webpack.config.js entrypoints like this:
entry: {
app: ["./src/scss/styles.scss", "./src/app.js"]
},
and styles.scss looks like:
#import '~bootstrap/scss/bootstrap';
#import '../css/feather.min.css';
#import '../css/icomoon-spinners.css';
#import url('https://fonts.googleapis.com/css?family=Maven+Pro:400,500,700,900');
#import 'helpers/variables';
#import 'helpers/mixins';
#import 'helpers/placeholders';
...
I am thinking css-modules might be the answer, but I can't figure out how to tell css-loader to make ALL styles local to #account-summary-container. I tried this in styles.scss:
:local(#account-summary-container) {
composes: "~bootstrap/scss/bootstrap";
composes: "../css/feather.min.css";
...
}
And it scoffed at my lame attempt with:
Error: composition is only allowed when selector is single :local class name not in ":local(#account-summary-container)", "#account-summary-container" is weird
I'm wondering if I am approaching it totally wrong. I'm hoping to not have to do alot of rewriting of styles.
In order to target only components inside of your Vue instance you have to use scoped styles. It is kind of a pain because you can't scope the css on the "main" App.vue file and let all children inherit it - you have to use scoped styles on each component that need it, which may result in more requests than you'd like..
As an example (I tested this and it should work)..
<template>
<!--
VUE/COMPONENT TEMPLATE
-->
</template>
<script>
export default {
/* ***********************
VUE/COMPONENT CODE
*********************** */
};
</script>
<!--
*********************************************************
***** SCOPE CSS PER COMPONENT ****************************
***** IMPORT VIA 'src="./path/to/cssfile.css"' ***********
**********************************************************
-->
<style scoped src="../css/style.css">
</style>
Found the answer. Pretty simple. Should had a V8 (conk).
.pony {
#import 'sub';
font-size: 100px;
}

How to isolate Vuetify global styles

I've started to use Vue.js with Vuetify within an old existing project. So I did not rewrite all frontend, I just imported Vue and replaced some parts.
And then I've noticed quite an unexpected behavior - Vuetify has global styles for common classes like .title and it effects the whole page, not only Vue part.
So, the questions is, how can I isolate vuetify styles inside Vue components?
UPD: As suggested #DigitalDrifter I tried to use stylus block-level import. So I removed
import 'vuetify/dist/vuetify.min.css'
from main.js and created a new .styl file (which was imported instead css) with the following content:
.vuetify-styles
#import '~vuetify/src/stylus/main'
And then added this class to the root component: <App class="vuetify-styles">
UPD2: After that you can get bug related to stylus compilation. More about it -> https://github.com/vuetifyjs/vuetify/issues/4864
UPD3: less also works fine for me.
# vuetify-styles.less
.vuetify-styles {
#import (less) '../../node_modules/vuetify/dist/vuetify.min.css';
}
And then just import it in your main.js
import './vuetify-styles.less'
Stylus supports block level imports.
If you've got the following:
// bar.styl
.bar
width 10px
// foo.styl
.foo
#import 'bar.styl'
The end result will be:
.foo .bar {
width: 10px;
}

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!

Angular-cli build generated CSS not working

I have an angular-cli app and using webpack.
When I try to run it the component specific css doesn't work
styles.css
/* You can add global styles to this file, and also import other style files*/
#import 'http://something/v4/dist/css/bootstrap.min.css';
Component
#Component({
selector: 'app-carousel',
templateUrl: './carousel.component.html',
styleUrls: ['./carousel.component.css']
})
export class CarouselComponent implements OnInit {
Component CSS
.carousel-indicators { display: none; }
angular-cli.config
"styles": [
"styles.css",
"../node_modules/roboto-fontface/css/roboto/sass/roboto-fontface-bold.scss",
"../node_modules/roboto-fontface/css/roboto/sass/roboto-fontface-light.scss",
"../node_modules/roboto-fontface/css/roboto/sass/roboto-fontface-regular.scss"
],
The rendered html
<style type="text/css">#import url(http://something/v4/dist/css/bootstrap.min.css);</style>
<style type="text/css">/* You can add global styles to this file, and also import other style files */
</style><style></style><style>.carousel-indicators[_ngcontent-c5] { display: none; }</style>
but this is not applied to my html element 'carousel-indicators'
If I import the carousel.component.cssinto the styles.css then it works but it appears twice in the generated html
I'm looking for the right way of doing this
By default(as in your case) angular using ViewEncapsulation.Emulated that scopes your css. However there is 3 view encapsulation options in Angular:
Native view encapsulation uses the browser's native shadow DOM implementation (see Shadow DOM on the MDN site) to attach a shadow DOM to the component's host element, and then puts the component view inside that shadow DOM. The component's styles are included within the shadow DOM.
Emulated view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing (and renaming) the CSS code to effectively scope the CSS to the component's view. For details, see Appendix 1.
None means that Angular does no view encapsulation. Angular adds the CSS to the global styles. The scoping rules, isolations, and protections discussed earlier don't apply. This is essentially the same as pasting the component's styles into the HTML.
So when you applying any styles to your component in component.css(with default ViewEncapsulation.Emulated) the styles will be applied just for that particular component, it won't be leaked outside the component and always have a priority above the global styles unless global style has !important.
So as a result you have the style in the head of your html file like:
<style>.carousel-indicators[_ngcontent-c5] { display: none; }</style>
If you referencing your component.css in styles.css then it will became a global style rendered in html head like so:
<style type="text/css">/* You can add global styles to this file, and also import other style files */
.carousel-indicators {
display: none; }
</style>
As you declared you style in competent and then referenced your component.css in styles.css that competent styles just gets doubled in your html: one copy is a global style and other copy is scoped component styles.
I was tried to replicate you issue but my compentnt.css is always gets applied. I am using the latest stable angular cli 1.3.2. If you are using older cli try to update. Otherwise push your code on github or create a plunker so I can take a look.
UPDATE: You might have your custom css gets overridden by some of your global stylesheets you are referencing. You can use chrome dev tools to debug the styles also you can try to put !important to your custom css and see if it does help.
For everybody landing here :
The issue was with the ViewEncapsulation.Emulated I changed it to ViewEncapsulation.None as describe in this stackoverflow answer :
how to hide ngb-carousel indicators and prev-next control
Thanks for your help

Angular 2 disable global styles inheritance in to child component

Is there a way to stop global styles to bleed in to child components without ViewEncapsulation.Native?
For example I have a global style
.container {
background: green
}
and a component
#Component({
template: html,
styleUrls: [url],
selector: 'dynamic-lp',
encapsulation: ViewEncapsulation.Emulated
})
The component is a dynamically added component with variable styleUrls and template html, so I don't want to inherit the green background if the template has a .container class.
If I change ViewEncapsulation.Emulated to ViewEncapsulation.Native all works as expected, but I would like to know if there's another way to achieve what I want since Shadow Dom is not supported by most browsers yet
UPDATE
I've found a solution which is working for me.
Wrap your sass imports in a "body:not(...)" assignment like this
body *:not(.innerhtml-container) {
#import 'bootstrap';
#import 'someother-plugin';
/* Components */
#import 'components/loading-bar';
#import 'components/textfield';
}
And add a container class "innerhtml-container" around the component template.
For example:
<div class="innerhtml-container"><div class="container">...</div></div>
this way no css inheritance will be passed on to the child component

Resources