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.
Related
I need to hash (or just prefix_) all CSS class names in a Vue CLI project to avoid class inheritance when I embed the app inside an existing HTML page.
Basically the Vue app/widget I've made uses some CSS class names like .title, .container, .date, .location etc, and the problem I've got is that the global CSS on the website where I'm embedding this Vue app already uses the class names .title, .container etc, so it's applying those styles to my Vue app as well. I just want a simple way — maybe using vue.config.js — to instruct webpack to randomly hash or prefix the CSS class names so that they are completely unique and won't inherit any parent styling. Thanks
Thanks to the comments above I managed to get it to work. The implementation is not as straight forward as I'd have liked because it requires changing a lot of my existing code — I was hoping for a quicker, simpler solution that would just take my existing code and hash the preexisting CSS classes — which I'm pretty sure must be possible as it seems like such a trivial task? Anyway, here's my setup for now:
vue.config.js
module.exports = {
css: {
requireModuleExtension: false,
loaderOptions: {
css: {
modules: {
localIdentName: '[hash:6]'
}
}
}
}
}
my-component.vue
<template>
<div :class="$style.myClass"> ... </div>
</template>
<style module>
.myClass {
color: red;
}
</style>
Using the above setup I get a div which, instead of being:
<div class="myClass"> ... </div>
is now rendered as:
<div class="_2d736c"> ... </div>
Note the module attribute on the <style> tag which is important. Also note the class name binding: :class (or v-bind:class) not just class.
Hope that helps someone. Thanks
I use vant ui components in vue, like buttons, I want to make a litte changes of it's style, like color, border ...., but I don't how to complete it, anyone could help me solve the problem? Thanks in advance!
I have tried add css or inline-style on element, but don't work!
Any custom component's css can be changed by using deep selector
GitHub Reference- https://github.com/vuejs/vue-loader/issues/913
Use ::v-deep in this case, as /deep/ will get deprecated.
Reference - Deep Selector
Just inspect class of the rendered element which you want to modify using devtools in chrome or any browser console.
Then, In you consuming component, modify it
<style scoped>
::v-deep vant-component-class {
background: red; //
}
</style>
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
So I just updated my project from Polymer v0.4.2 to v0.5.1 of the Polymer library. One thing that seemed to have changed is how the paper-dialog element is implemented.
In v0.4.2, when I had a paper-dialog inside of my custom element, I could customize it with CSS inside of my element using core-style elements.
In v0.5.1, if I understand correctly, the paper-dialog is no longer implemented inside my component, but instead it's implemented in the core-overlay-layer element which is in the html page outside of my component.
So does that mean that I now have to add a CSS style sheet to the html page that contains my component? If so, then I can no longer use core-style along with the benefits of the CoreStyle.g object. It also means that everything related to my component is no long all encapsulated inside of my component.
Please tell me that I am wrong and that there is a way for me to style the paper-dialog from within my component still.
Thanks!
In Polymer 0.5.1 the layered property (doc: https://www.polymer-project.org/docs/elements/core-elements.html#core-overlay) defaults to true which allows it to always display above page content. If layered is false, the dialog may not display on top if there is something after it in DOM with a higher stacking context.
However because layered reparents the dialog to a global core-overlay-layer it's not possible to style it from an outer scope. There are a couple options for styling:
If you know you don't have any DOM with a higher stacking context than the dialog, set layered="false" to get the non-layered behavior and you can style it from the outer scope.
Style the dialog with a /deep/ rule in a global style. You can still use core-style by referencing the style in the global scope. You can also include it in the same file as your element definition, e.g.
<core-style id="x-dialog">
html /deep/ #dialog {
color: red;
}
</core-style>
<core-style ref="x-dialog"></core-style>
<polymer-element name="my-element" noscript>
<template>
<paper-dialog id="dialog"></paper-dialog>
</template>
</polymer-element>
Extend paper-dialog and style the new element:
<polymer-element name="my-paper-dialog" extends="paper-dialog" noscript>
<template>
<!-- or use core-style -->
<style>
:host {
color: red;
}
</style>
</template>
</polymer-element>
Live examples: http://jsbin.com/subanakuna/1/edit?html,output
For example I could do the next thing:
<polymer-element name="hello-world">
<template>
<div style="background-color: red">
hello world!
</div>
</template>
</polymer-element>
Furthermore, I could also style the element dynamically doing the next:
HelloWorld.create() : super.create() {
createShadowRoot().children = [
new DivElement()
..style.color = SOME_GLOBAL_COLOR
..text = 'Hello World!'
];
}
Instead of:
<polymer-element name="hello-world">
<template>
<style>
.somediv {
background-color: red;
}
</style>
<div class="somediv">
hello world!
</div>
</template>
</polymer-element>
It is considered good practice. It provides encapsulation.
The selectors like /deep/ can reach into the element, that makes it easy to override styles from the outside for example for theming or customization.
Styles from the outside have higher priority too, to make this easy.
Styles using the /deep/ combinator can cause performance problems especially on browsers that don't support shadowDOM natively but use the polyfills.
I would provide basic/default styling inside the component and site-specific customization outside the element.
The verbosity (and indirectly complexity) of the component style is the criteria to keep an eye on. I personnally find one-file components easier to maintain.
Aside this organizational consideration, as style elements are part of the template, observable (hence published) properties can be put directly inside the css. This is quite handy especially to:
provide handles to external customization.
dynamically update some css properties, like element box height.