Is vuejs component's style global to other components - vue.js

I have two pages:
search.php that contains a vuejs component called search.vue
person.php that contains another component called person.vue.
In search.vue, I have links to person.php.
How come the styles set in the component search.vue also affect the DOM in person.vue?
The style tag in my search.vue component:
<style>
.row {
background-color: red;
}
</style>
There is nowhere I connect these two views except through the href link to open the person.php page.

Styles defined in the style tag of a Vue single-file-component will be compiled to a singular file, affecting all components.
But, you can specify a scoped attribute on the component's style tag:
<style scoped>
.row {
background-color: red;
}
</style>
From the Documentation:
The optional scoped attribute automatically scopes this CSS to your component by adding a unique attribute (such as data-v-21e5b78) to elements and compiling .list-container:hover to something like .list-container[data-v-21e5b78]:hover.
Note that the scoped attribute is a Vue feature for single-file-components, different from the general scoped style tag attribute, which has a similar effect but is currently only supported by Firefox.

Related

Vue.js (v3): How to have a unique data-v-* hash for each component instance

I have the following code:
blah-foo.vue:
<template>
<div>Hello {{ name }}</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
props: {
name: {
type: String,
}
},
});
</script>
<style scoped>
div {
color: white;
}
</style>
and App.vue:
<template>
<blah-foo
name="Alice"
></blah-foo>
<blah-foo
name="Bob"
></blah-foo>
</template>
The result in my browser is the following:
<div data-v-73bdd40c>Hello Alice</div>
<div data-v-73bdd40c>Hello Bob</div>
Is there any way I could tell the vue loader to generate an unique data-v-* attribute for each of them ?
What is happening in production is that since the component blah-foo is called on many different lazy-loaded pages, I end up having many times
div[data-v-73bdd40c] {
color: white;
}
all overriding each other.
That isn't a problem in itself, it just does seem very disgraceful (code wise) after having loaded a few pages when inspecting elements.
That is not possible with vue-loader. And it shouldn't be done anyway.
The whole point of the data-v-xxx attribute is to identify the components in the DOM so vue can apply to them the correct scoped css.
If it ever applied uniq data-v attributes, it would not be able to apply the correct css.
I understand your problem is that, on production, you see in the css inspector several times the css code, right?
My guess is that it's related with sourcemaps, which may mess with the css inspector. But I can't help more without additional details on your project configurations.
Even if your component is used on several pages, its module will be fetched and loaded only once. You don't have the scoped css loaded several times, it's just an inspector problem.

Vue 3: Styling a Named Slot

So I've looked through stackoverflow and the documentation in Vue 3 but can't quite find what I'm looking for.
I'm trying to find a way to target a named slot, penetrate the scoped element within that slot, and override one of its children's styles. I assume I need the ::slotted selector and the :deep selector for this mission. Does anyone know how to do this?
Here is an example of the situation I am trying to solve for (LayoutContainer Component):
<section>
<slot name="text"></slot>
<slot></slot>
<slot name="sidebar"></slot>
</section>
the component that will go into the "text" slot (Eyebrow Component):
<section class="eyebrow-container">
<h1>{{title}}</h1>
<h6>{{description"}}</h6>
</section>
a completed view of the code on a page component:
<LayoutContainer>
<template #text>
<Eyebrow :title='test' :description="this is a description"></Eyebrow>
</template>
<PageBody></PageBody>
<template #sidebar>
<PageSideBar></PageSideBar>
</template>
</LayoutContainer>
Solutions I have tried in SCSS with no success:
::slotted(h6) { color: red }
::slotted(text){
:deep(.eyebrow-container) {
h6 { color: red; }
}
}
::slotted(text) {
:deep(h6) { color: red; }
}
and a few others I have forgotten at this point.
Does anyone have any ideas on how to get to the h6 tag inside of the Eyebrow Component from the Page Component's SCSS?
The slot content is owned by the parent passing them in.
So you don't need to use :slotted. You can simply use the :deep selector
<style scoped>
:deep(h6) {
color: red;
}
</style>
See it live
If you are wondering how to use :slotted then in your case it would be used in LayoutContainer component trying to style what the parent component passes in.
Scoped styling and styling child components from a parent don't work as you might think if you use multi-root node components.
So if you use mutli-root node component and :deep doesn't work, See my other answer

How to apply a body {} style to specific vue component

I'm using scoped style for most of my components to not interfere with other components.
Some of my views/components need body { overflow: hidden; }, but others don't.
I can't use
<style scoped>
body {
overflow: hidden;
}
...
</style>
How can i apply this style when specific components are loaded? (i am using vue router if that helps)
You may send a prop to your component like described in here: https://v2.vuejs.org/v2/guide/components-props.html
Let's call you prop isOverflowHidden, and create .hidden class in your css.
After that, you can add your wrapper element (first tag in component) :class="{ hidden: isOverflowHidden }"
Or you can move it to a method.
If you want you can use this this action for inline-styling.
<div :style="{ overflow: (isOverflowHidden ? 'hidden' : '')}"></div>
You can read extended information in here: https://v2.vuejs.org/v2/guide/class-and-style.html#Binding-Inline-Styles

Conditionally override css in Style tag

Assuming I am using a plugin that generates html at runtime where I cannot edit the CSS or JS code, leaving me with the only option of overriding certain CSS in particular classes. For instance, in such case I'd often do:
.video-player{
max-height: 500px !important;
}
In case such styling must be handled conditionally based on the props passes to the component, for instance:
<videoPlayer :goSmall="anotherColumn != null"></videoPlayer>
since the CSS in the videoPlayer components must go in the Style tag:
<style scoped>
.video-player{
max-height: 500px !important;
}
</style>
how can I render it conditionally?
It is such a bad idea to append it to the DOM using lifecyle hooks, so please do not suggest anything like that.
Why not apply a specific class to the component instead of passing a prop?
<videoPlayer :class="{ small: anotherColumn != null }"></videoPlayer>
And the css
<style scoped>
.video-player.small {
max-height: 500px !important;
}
</style>
If you are not okay with dynamically applying CSS using lifecycle hooks. You can always box your components. Make two components for your videoPlayer, we'll call them videoPlayerOriginal and videoPlayerSmall.
//videoPlayerOriginal.vue
<videoPlayer></videoPlayer>
Add your css in videoPlayerSmall.vue
//videoPlayerOriginal.vue
<videoPlayer></videoPlayer>
<style scoped>
.video-player{
max-height: 500px !important;
}
</style>
Now render either one of them conditionally.

What's the difference between `scoped` and `module` in vuejs components?

I understand that with 'scoped' i can isolate css stylings to a component, so What's the difference between scoped and module in vuejs components? When should I use module over scoped?
According to the docs:
CSS Modules as an alternative for simulated scoped CSS
So, it's an alternative - It's also worth noting that scoped on a parent component means child components can't see the CSS but with module you can access this.$parent.$style.red to gain access to the styling.
It does however have the added advantage that you can then access your CSS from within your code:
<style module>
.red {
color: red;
}
</style>
<script>
export default {
created () {
console.log(this.$style.red)
}
}
</script>