I've just hit a wall with custom-style. Unfortunately it seems that any mixins and variables are applied to descendants of elements matched in the Light DOM. On the other hand the :root selector applies the vars and mixins to all custom elements.
Isn't there a middle ground where it would be possible to style eg. any custom element that has a given class etc? For example I would like to have
<style is="custom-style">
my-element.important {
--border-color: red;
}
</style>
To set the variable for each instance of <my-element> withe the given class. Currently it only works for elements in the Light DOM (for document level style) and Local DOM (when setting variables/mixins inside other element). It also doesn't work for anything like :root my-element or :root /deep/ my-element or html /deep/ my-element
I've prepared a reproduction on Plunker.
The solution is quite simple, as pointed out by #lozandier and Karl on Polymer's Slack channel.
For document-level styles the property groups must be wrapped in with :root selector
<style is="custom-style">
:root {
my-element.important {
--border-color: red;
}
}
</style>
And for style inside element it's necessary to use :host instead
<dom-module>
<template>
<style>
:host {
my-element.important {
--border-color: red;
}
}
</style>
</dom-module>
</template>
Related
I have a project in Vue 2.x and I am wondering why targeting a child component's class works without using the /deep/, ::v-deep or >>> selectors.
I am using these within the project:
"node-sass": "5.0.0",
"sass": "1.32.12",
"sass-loader": "10.1.1",
Additionally I have created a sandbox to demonstrate the issue in real time.
If I am in a parent component I am able to target a child component even within scoped styles like this:
<style lang="scss" scoped>
.parent-component {
.child-component {
/* I set the child components background color even though I don't use a `deep` selector */
background-color: blue;
}
}
</style>
And in the child component I have:
<style lang="scss" scoped>
.child-component {
/* I'm overwritten by the parent component */
background-color: red;
}
</style>
From my understanding of how scoped styles work, this should not actually work without me doing something like this in the parent:
<style lang="scss" scoped>
.parent-component {
::v-deep .child-component {
background-color: blue;
}
}
</style>
You can affect only root element of child component without using ::v-deep. If you write like this, the style will not be applied.
<template>
<div>
<div class="child-comp">
How in the world am I styled without /deep/ or ::v-deep or >>>
</div>
</div>
</template>
With a normal React/Vue component I normally create a custom CSS class and use that to style the component like so:
<div class="foo">
...
</div>
.foo {
}
With web components, there is the additional option to use the :host psuedo-selector. I understand that it can be used to apply styles to the web component HTML element itself.
<div class="foo">
...
</div>
.foo {
}
:host {
}
When should I use :host versus a custom CSS class like .foo?
An important part you do not mention, is that React (and other Frameworks), in the build step, rewrites all your classNames, to create "unique" class names.
React does not scope CSS like shadowDOM does.
Below answer is for a Web Component with shadowDOM;
Note that shadowDOM can be attached to regular DOM Elements as well. Same answer applies.
:host refers to your ... host...Web Component DOM element: <my-element>
Bluntly said, you could compare it to html,head,body in global CSS, it is the container element
The CSS inside does not (have to) know the element name my-element
classes (or any CSS selector you know) style Web Component content
OR, if you are not using shadowDOM, they style your whole document,
because unlike Frameworks, classNames are not changed, to be "unique", in the Build step.
And do learn <slot> behaviour:
::slotted CSS selector for nested children in shadowDOM slot
<style>
.foo {
border:1px solid red; /* CSS not applied to elements in shadowDOM */
font: 30px Arial; /* for UX consistancy, font styles DO style shadowDOM */
}
</style>
<span class="foo">
<my-element>Hello</my-element>
Web Components
<my-element pink>World</my-element>
</span>
<template id="MY-ELEMENT">
<style>
:host {
display:inline-block;
background:lightgreen;
}
:host([pink]) { background:hotpink }
.foo { font-weight:bold; /* does NOT style anything outside this shadowDOM */ }
</style>
<slot class="foo"></slot>
</template>
<script>
customElements.define('my-element', class extends HTMLElement {
constructor() {
super().attachShadow({mode: 'open'})
.append(document.getElementById(this.nodeName).content.cloneNode(true));
}
});
</script>
I'm trying to get my head around the not selector is css. I'm trying to hide a div called "InfoRow" if the page doesn't have a class of 'home'
My first stab at this:
:not(body.home #InfoRow) {
display:none;
}
From MDN:
The :not() CSS pseudo-class represents elements that do not match a list of selectors. Since it prevents specific items from being selected, it is known as the negation pseudo-class.
:not(.foo) will match anything that isn't .foo, including <html> and <body>
As the class .home would be set on the <body> tag, and #InfoRow is a child of <body>, you'd have to write it like this:
body:not(.home) #InfoRow {
display: none;
}
I am using vue js's ELEMENT UI. And i want to override its style. I can do it with global style. But scoped style doesnt work. When i used global style it changes my all pages design. but i want to do it just for one page.
Here is my style(global style. and this is working):
<style>
.el-icon-close:before{
content: "Back" !important;
}
</style>
but when i used scoped it doesnt work:
<style scoped>
.el-icon-close:before{
content: "Back" !important;
}
</style>
Is there any idea about this?
The scoped keyword means that this the changes to the style will apply only to the elements in the current scope. Meaning all custom made elements in the page. If you want to access elements "created" somewhere else you will have to skip the scoped keyword. The code that is in the scoped tag will apply only for the current page/view else it will apply for all pages/views.
All not scoped elements usually are style in the App.vue file. If you want to apply style of element that is not scoped just wrap it in a div add the class to it and style it in the scoped tag:
<style scoped>
.my-custom-div{
.el-icon-close:before{
content: "Back" !important;
}
}
</style>
Atleast that is working with me.
You must use custom class:
.custom-class{
smthng goes here...
}
This is achievable with Deep selectors
For your use case:
<style scoped>
.parent-div /deep/ .el-icon-close:before{
content: "Back" !important;
}
</style>
As I understand :host-context is used to apply styles based on selector of parent.
Lets consider a rule as follows:
:host-context(.red-theme) { background-color: red; }
same can be written using :host selector as folows:
.red-theme :host { background-color: red; }
Then whh is host-context explicitly required?
Use :host if you want to style the component custom HTML element itself.
Where as :host-context is used when you also want to have a component apply a style taking into account context in which component is rendered.
So for example, you could do: (with host-context)
<div class="red-theme">
<app-component></app-component>
</div>
where app-component
<button class="btn btn-theme">Button</button>
and the component style is defined:
:host-context(.red-theme) .btn-theme {
background: red;
}
Useful if you want to have multiple alternative themes on your web application.
:host and :host-context are not Angular features, but CSS features.
Within the demo provided at stackblitz.com/edit/angular-z3xxtu, the Angular components are merged into the DOM and allow plain old CSS selector structure like .parent :host .child { color: red; }.
This changes when using Webcomponents and ShadowDOM.
The ShadowDOM acts as a barrier and encapsulates the contained markup and style, so the .parent cannot style the things on the :host and vice versa. Note cannot is not totally true, see ::part and CSS Custom Properties.
With a structure like <parent> <my-component> ShadowDOM <child> the above CSS rule no longer works and :host-context(.parent) (which could be read as .parent :host) is needed. Sadly as of 2023-01-10 this doesn't work in Firefox and Safari.
In the above demo, :host-context(.red) { color: red; } and .red :host { color: red; } produce the same output because there's no ShadowDOM involved. On top of that, Angular transforms the invalid .test :host in the CSS to .test [_nghost-some-id] which is a valid CSS selector.