Reputation: 53
I have two custom element:
<name-card data-color="#000000"></name-card>
<name-card data-color="#80B88C"></name-card>
which I will applied their data-color
to the style.
From I asked question before, how to get cssRules, I got the answer and added it to attachedCallback()
for dynamic changes.
But, it just shows the right colour on chrome, other browser applied the last colour which is #80B88C
to both.
I checked the loop in attachedCallback()
for(i = 0; i < rules.length; i++){
if(rules[i].selectorText === '.base'){
rules[i].style.background = bgColor;
}
}
and both changed the correct colour, but I still have no idea why they will applied the last colour to both elements style on safari and firefox.
Upvotes: 3
Views: 128
Reputation: 31209
This is due to the fact the polyfill cannot realize totally the css isolation.
So the CSS stylesheet that you add in a polyfilled Shadow DOM is in fact applied to the whole document. When the same name rule is used twice, the last one wins. That's why you observe this behaviour in Safari and Firefox.
There's a workaround to this issue in your case, which deals with the ::before
and ::after
pseudo-elements:
Curent Solution
cssRule
which includes the specific color:Inside the attachedCallback()
function:
sheet.insertRule( '[data-color=' + bgColor + '] .base::before { background: ' + bgColor + ' ; }', sheet.length )
Future Solution
When the the CSS 3 specification for attr()
on every properties will be implemented:
attr()
CSS function to apply the right color, passed by attribute (data-color
in your example).The advantage of this solution is that it works the same way will polyfill and native implementation, and with an unlimited number or colors.
In the attachedCallback()
function:
var targets = this.querySelectorAll( '.base' )
for ( var i = 0 ; i < targets.length ; i++ )
{
targets[i].dataset.color = bgColor
}
In the <style>
element:
.base::before {
background: attr( data-color )
}
var proto = Object.create( HTMLElement.prototype )
proto.createdCallback = function ()
{
this.createShadowRoot()
var tmpl = document.querySelector( 'template' )
this.shadowRoot.appendChild( tmpl.content.cloneNode( true ) )
}
proto.attachedCallback = function ()
{
//get custom color
var bgColor = this.dataset.color
//add it to the top-level inside Shadow DOM
this.shadowRoot.querySelector( 'section' ).dataset.color = bgColor
//change the stylesheet in the next microtask
var style = this.shadowRoot.querySelector( 'style' )
setTimeout( function ()
{
var sheet = style.sheet
sheet.insertRule( '[data-color=' + bgColor
+ '] .base::after { background: ' + bgColor + ' ; }'
, sheet.cssRules.length )
} )
}
document.registerElement( 'name-card', { prototype: proto } )
<name-card data-color="red"></name-card>
<name-card data-color="green"></name-card>
<template>
<style>
.base::after {
content: '-postfix' ;
}
</style>
<section>
<div>Custom Element</div>
<span class="base">Base element</span>
</section>
</template>
Upvotes: 0