After reading Monica's article "::part and ::theme, an ::explainer" , I am experimenting with the CSS ::part
selector, and the corresponding shadow-DOM elements' part
attribute in HTML web components. Now I have some CSS styling issues and I cannot find any specific documentation about it.
To illustrate the issue, I have created a custom element called my-box
. Its shadow-DOM just contains a div
element with a width and height of 100px. When clicked, the div
will get a CSS class marked
assigned to it and thus it will be considered to be "marked".
By default, the my-box
component will be styled:
This styling is defined in a style
tag in my-box
's shadow-DOM.
Furthermore, to allow external styling of the shadow-DOM's div
element, I assign the value "box" to its part
attribute. That way, it can be externally referred to using the ::part()
CSS selector.
Here's my initial HTML test file's content:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type="module">
customElements.define("my-box", class extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.innerHTML = `
<style>
:host {
display: block;
}
div {
height: 100px;
width: 100px;
background-color: lightcoral;
}
div:hover {
background-color: red;
}
div.marked {
background-color: lightblue;
}
div.marked:hover {
background-color: blue;
}
</style>
<div part="box"></div>
`;
const div = shadowRoot.querySelector(":scope div");
div.addEventListener("click", () => {
div.classList.add("marked");
});
}
});
</script>
</head>
<body>
<my-box>
</my-box>
</body>
</html>
So far so good. But now I want to externally style the my-box
component with the following styling:
For that purpose, I tried to add the following CSS styling to my test HTML's head:
<style>
my-box::part(box) {
background-color: lightgreen;
}
my-box::part(box):hover {
background-color: green;
}
my-box::part(box).marked {
background-color: lightyellow;
}
my-box::part(box).marked:hover {
background-color: yellow;
}
</style>
But this seems to work only partially. As expected, the green color palette for the unmarked state works correctly. However, the yellow palette for the marked state does not work: the green color palette is also used when the element is marked.
So I guess that the CSS rules for the yellow color palette are invalid. The ::part()
selector probably cannot be combined with such class selectors (defined in the shadow-DOM).
Does anybody know how I could get that yellow color palette to work for marked elements? Preferably in a nice and elegant way?
Thanks in advance!
I had an epiphany during supper... ;)
What about simply using the div
element's part
attribute in combination with the class
/ classList
attribute for "marking" the div
element?
So I updated my click eventlistener by adding a statement that sets the div
's part
property so that it includes a new part name box-marked
. And I updated the external CSS selectors to use the new box-marked
part name for the yellow color palette.
So I tried this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
customElements.define("my-box", class extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.innerHTML = `
<style>
:host {
display: block;
}
div {
height: 100px;
width: 100px;
background-color: lightcoral;
}
div:hover {
background-color: red;
}
div.marked {
background-color: lightblue;
}
div.marked:hover {
background-color: blue;
}
</style>
<div part="box"></div>
`;
const div = shadowRoot.querySelector(":scope div");
div.addEventListener("click", () => {
div.classList.add("marked");
div.part = "box box-marked";
});
}
});
</script>
<style>
my-box::part(box) {
background-color: lightgreen;
}
my-box::part(box):hover {
background-color: green;
}
my-box::part(box-marked) {
background-color: lightyellow;
}
my-box::part(box-marked):hover {
background-color: yellow;
}
</style>
</head>
<body>
<my-box>
</my-box>
</body>
</html>
This seems to do the job.
However, I am not sure if the part
attribute of HTML elements in the shadow-DOM is (or will be) intended to be used this way. If so, it would be nice if the Element
class in JavaScript will also get a comfortable partList
property (analogous to its classList
property) in the near future. For now, I simply used the part
property directly.
Also, the current version of Firefox (68) has issues with handling the example code. The :scope
pseudo class has to be removed from the querySelector
call's argument to make it find and return the div
element. And I also have to use the div
element's setAttribute
method to change its part
attribute, because it does not seem to have implemented the Element.part
property just yet. (The Element.part
property doesn't seem to be documented on MDN yet either.)
However, even when all that is adjusted, Firefox still does not seem to be capable of parsing the external CSS that uses the ::part()
pseudo element for setting the green and yellow color palettes at all; only the internal (shadow-DOM) red and blue color styling is working, even with the external CSS in place.
All the above mentioned issues with Firefox are understandable, of course, since this functionality is still considered to be experimental technology. Regrettably, I have not been able to find an actual browser support overview on Can I Use to validate the current implementation status in Firefox.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.