NOTE THe below question is flawed, please rather refer to: Suspected Chrome bug: CSS `last-of-type` not updating in webcomponent if apply certain styling
Below you will see a list of gray blocks, items 111
to 555
. 2 Seconds after running another item will be created via JS and appended to the list. The NEW
item will be styled as last-of-type
, but the previous last-of-type
will remain styled as if was last-of-type, but it no longer is!
My current fix is when appending a new item to the list, hide the old last item (555
) in this case, then show it again, this is done by setting display: none
then display: block
. Unfortunately it results in a flicker on more complex web components. Is there any way to make last-of-type
update with a flicker? Am I using last-of-type
incorrectly? Is it a Chrome bug?
class Component extends HTMLElement {
constructor() {
super().attachShadow({mode:'open'});
const template = document.getElementById("TEMPLATE");
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
window.customElements.define('wc-foo', Component);
setTimeout( () => {
const child = document.createElement('div')
child.textContent = "new"
child.classList.add('child')
CONTAINER.appendChild(child)
}, 2000)
#CONTAINER .child:last-of-type {
border: 1px solid red;
}
<template id="TEMPLATE">
<style>
:host {
background: gray;
display: block;
}
</style>
<slot>
WC-FOO
</slot>
</template>
<div id="CONTAINER">
<wc-foo class="child">111</wc-foo>
<wc-foo class="child">222</wc-foo>
<wc-foo class="child">333</wc-foo>
<wc-foo class="child">444</wc-foo>
<wc-foo class="child">555</wc-foo>
</div>
Opened this bug report in the meantime: https://bugs.chromium.org/p/chromium/issues/detail?id=1417953
This isn't a bug, it's working as designed (and expected). :last-of-type
refers to the element-type, not the class-name, of an element; therefore the last wc-foo
– regardless of its class-name – remains the :last-of-type
even when it has an adjacent sibling with the same class-name; as the documentation says:
...The
:last-of-type
pseudo-class represents an element that is the last sibling of its type.
Citation: https://www.w3.org/TR/selectors-3/#last-of-type-pseudo.
To demonstrate, instead of a <div>
element we can add a <wc-foo>
element:
class Component extends HTMLElement {
constructor() {
super().attachShadow({
mode: 'open'
});
const template = document.getElementById("TEMPLATE");
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
window.customElements.define('wc-foo', Component);
setTimeout(() => {
const child = document.createElement('wc-foo')
child.textContent = "new"
child.classList.add('child')
CONTAINER.appendChild(child)
}, 2000)
#CONTAINER .child:last-of-type {
border: 1px solid red;
}
<template id="TEMPLATE">
<style>
:host {
background: gray;
display: block;
}
</style>
<slot>
WC-FOO
</slot>
</template>
<div id="CONTAINER">
<wc-foo class="child">111</wc-foo>
<wc-foo class="child">222</wc-foo>
<wc-foo class="child">333</wc-foo>
<wc-foo class="child">444</wc-foo>
<wc-foo class="child">555</wc-foo>
</div>
References: