Why can't I target my custom-defined HTML elements in CSS? - html

In my HTML, I've got:
<link rel="stylesheet" href="css/styles.css">
<script src="js/components/custom.js"></script>
...
<custom></custom>
In custom.js, say I've defined:
class Custom extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = `
<style>
#import url('/css/styles.css');
</style>
...
`
}
}
customElements.define('custom', Custom)
In styles.css, when I define styles, they work. But I can't do something like
custom img {
}
to target an img inside custom. I have to use wrappers like div.custom-contents to target elements within.
Is this a known limitation perhaps with #imports like this, custom elements in general, or am I doing something wrong?

It is mandatory for custom elements that the name must consist of at least one letter, followed by a - dash, then at least one other letter. Your web component will not work if you don't conform to that requirement.
Your component uses shadow DOM. No outside styles affect the shadow DOM (other than inheritance), and no styles in the shadow DOM affect elements outside of of your component. This is the main concept behind shadow DOM - components bring their styling, and don't affect other elements on the page they're used in.
Also, you shouldn't attach the shadow DOM in the connectedCallback. That should always be done in the constructor.
You can use the part attribute along with the ::part pseudo element to allow styling from the outside.

Related

How to cancel stylesheets rules for certain elements in page

I using ANTD framework for building an app.
And latelly i noticed one small issue with one of ANTD elements when i import antd-theme.css
For some reasons that css overides rules for one ANTD elements and makes it look terrible.
I cannot refuse from using this css stylesheets because it's needed for other elements all over the app.
So it's imported in index.js
Also i cannot overide this rule which breaks ANTD element, because it's stylesheet has 24844 lines.
And i will never find what exectly breaks it.
Believe me I tried:(
I was curiouse is there some how possible to make some element/elements ignore certain stylesheets?
Like something
<Radio style={{igonereCss}} />
I think you can give your element a class that you define and it will use that over the other styles
<radio class="mystyle">
Then in your main css style sheet just define a style for that. It doesn't have to do anything, but it might override the styles that are happening elsewhere.
.mystyle {
}
you can change style of specific component by overriding default class in your css file (you will get all the element classes from developer tool) for that element
.ant-radio-checked .ant-radio-inner{
background-color:#fdfdfd !important;
}
as a result it will override the style globally, to override the style for specific component only just wrap the component in some div by giving class "test" and override the css
.test .ant-radio-checked .ant-radio-inner{
background-color:#fdfdfd !important;
}
and it will update the style for specific component only

Why does this globally defined css rule affect styling inside of the shadow DOM?

I created an web-component with shadow mode 'open', which is used like this:
<scu-switch checked="true" value="switch1">
<span id="scu-switch-label">Switch On</span>
</scu-switch>
and looks like this:
Than I added the button to a webpage with the following global CSS:
text-align: center;
and now the button style is broken:
When I inspect the button I can see, that the global style was applied to the span (and notice that it is not part of slot content) inside of the shadow root.
The shadow DOM is supposed to isolate style from the rest of the web page.
Why was this text-align: center applied here, even though it was defined outside of the Shadow DOM?
One of the great features of the Shadow DOM in Web Components is that styles are encapsulated to the component - you can style your component without worrying about any specifier (id, class, etc.) conflicts or styles 'leaking out' to other elements on the page.
This often leads to the belief that the reverse is true - that styles outside of the component won't cross the Shadow boundary and 'leak in' to your component. However this is only partly true.
While specifiers do not leak in to your component (e.g. a color applied to an p element in a style rule outside of your component won't effect any p elements in your Shadow DOM, although the rule will be applied to your Light DOM, or slotted content),
inheritable styles applied to any elements containing your component will be applied to both your Shadow and Light DOM.
Source: https://lamplightdev.com/blog/2019/03/26/why-is-my-web-component-inheriting-styles/

How to style deep inside shadow trees

I have a problem with styling deep shadow trees. How can i apply some styles into shadow-dom ?
Here is i tried:
<link rel="import" href="../../bower_components/polymer/lib/elements/custom-style.html">
<custom-style>
<style is="custom-style">
vaadin-text-field [part='input-field']{
display: none;
}
</style>
</custom-style>
But its not working. Any advice ?
My understanding is that you can't, see:
https://www.polymer-project.org/2.0/docs/devguide/style-shadow-dom
"The HTML elements in your template become children in your custom element's shadow DOM. Shadow DOM provides a mechanism for encapsulation, meaning that elements inside the shadow DOM don't match selectors outside the shadow DOM."
Instead you need to extend the webcomponent, making custom version of it with your styles, the linked documentation gives information on that too.
you can use vaadin-themable-mixin to style parts elements.
But please note that once theme is loaded, it's will become global, so that all vaadin control in your website is styled by your theam.
read more at:
https://github.com/vaadin/vaadin-themable-mixin/wiki/1.-Style-Scopes

Tool for CSS extraction (and scope adjustment)

I have a webpage with a main parent div tag
<div class="mainDiv">...</div>
that contains a very large number of child elements. The page has an external stylesheet with mostly element selectors instead of class selectors:
Eg.
img {...}
instead of
.myImgCls {...}
I need a stylesheet that contains the global (page) css applied only to my mainDiv div tag, so that I can easily inject my mainDiv html on any page, along with that new stylesheet, without interfering with the new page's element selectors.
So, am basically looking for a tool that will generate something like:
.mainDiv img {...}
for everything inside my mainDiv.
Doing this manually is out of the question, because of the large number of elements in mainDiv.
To further elaborate: need this for jplist, which comes with a standard jplist.demo-pages.css; however instead of styling only the jplist instance, that standard jplist.demo-pages.css contains mostly element selectors so if I want to directly add a standard jplist instance on a page, I'd have to use jplist.demo-pages.css and that would interfere with my page's original stylesheet.
If you're looking for an easy way to nest all those elements within the main div, you could try Sass:
.mainDiv
// Child selectors go here
Note: Indentation is important.

Light DOM styles "leaking" into Polymer component's shadow DOM

I have a polymer web component which has a div named content, within the component.
I have noticed that if the host page has a style for div.content then it applies that style to my component!
This is an unexpected turn of events since web components are supposed to prevent light DOM styling from leaking into the component. In addition, I am using the following css rule which is supposed to prevent such a thing from happening:
:host {
all: initial;
}
Any ideas?
Polymer by default doesn't use shadow-dom. It uses an approximation of it called shady dom, which doesn't provide style encapsulation and everything is dumped into light dom.
If you want to enable shadow dom by default, you can do so by using this config:
<script>
window.Polymer = window.Polymer || {};
window.Polymer.dom = 'shadow';
</script>