problem adding adopted style sheets while using webcomponents with google chome and developer tools opened

513 Views Asked by At

I have problems adding adoptive style sheets for my webcomponent instances into the document.

My custom webcomponent creates a new CSSStyleSheet instance in the constructor. When the component gets upgraded by the connectedCallback it adds the instance into the document.adoptedStyleSheets. Then I have an update()-Method which can be called later to change the css properties of the adopted style sheet.

In the following examples you can see the usage. My HTML contains two custom components and some buttons for adding and remove style properties.

We can add different styles to both components by using the add buttons. Everything works fine until the developer properties are not open. If you open the developer properties and reload the example, it seems that both CSSStyleSheet instances added to the adoptedStyleSheets are referencing to the same instance.

Clicking "Apply Style" Button next to Element 1 will add a green border to element 1.

Clicking "Apply Style" Button next to Element 2 will add a black border to element 2.

But it removes the styling of Element 1. This should not happen cause the CSSStyleSheet object of Element 1 still should have the css properties for himself. But they get lost.

class CustomElem extends HTMLElement {
  
  constructor() {
    super();
    this.myStyle = new CSSStyleSheet();
  }

  connectedCallback() {
    document.adoptedStyleSheets = [ ...document.adoptedStyleSheets, this.myStyle ];
  }
  
  update(css) {
    this.myStyle.replaceSync(css);
  }
}

customElements.define('custom-elem', CustomElem);

document.getElementById('btn1_add').addEventListener('click', function() {
  document.getElementById('elem1').update('custom-elem#elem1 { border: 3px solid green; }');
});

document.getElementById('btn2_add').addEventListener('click', function() {
  document.getElementById('elem2').update('custom-elem#elem2 { border: 3px solid black; }')
});

document.getElementById('btn1_remove').addEventListener('click', function() {
  document.getElementById('elem1').update('');
});

document.getElementById('btn2_remove').addEventListener('click', function() {
  document.getElementById('elem2').update('')
});
<html>
  <head></head>
  <body>
    Custom Elements<br /><br/>
    <custom-elem id="elem1">Element 1</custom-elem>
    <input type="button" id="btn1_add" value="Apply Style"></input>
    <input type="button" id="btn1_remove" value="Remove Style"></input>
    <br /><br />
    <custom-elem id="elem2">Element 2</custom-elem>
    <input type="button" id="btn2_add" value="Apply Style"></input>
    <input type="button" id="btn2_remove" value="Remove Style"></input>   
  </body>
</html>

My second Example fixes this problem. If I call replaceSync('') directly in the connectedCallback, everythink works like expected.

class CustomElem extends HTMLElement {
  
  constructor() {
    super();
    this.myStyle = new CSSStyleSheet();
  }

  connectedCallback() {
    document.adoptedStyleSheets = [ ...document.adoptedStyleSheets, this.myStyle ];    
    // *****************************
    // this makes it work!
    // *****************************
    this.myStyle.replaceSync('');
  }
  
  update(css) {
    this.myStyle.replaceSync(css);
  }
}

customElements.define('custom-elem', CustomElem);

document.getElementById('btn1_add').addEventListener('click', function() {
  document.getElementById('elem1').update('custom-elem#elem1 { border: 3px solid green; }');
});

document.getElementById('btn2_add').addEventListener('click', function() {
  document.getElementById('elem2').update('custom-elem#elem2 { border: 3px solid black; }')
});

document.getElementById('btn1_remove').addEventListener('click', function() {
  document.getElementById('elem1').update('');
});

document.getElementById('btn2_remove').addEventListener('click', function() {
  document.getElementById('elem2').update('')
});
<html>
  <head></head>
  <body>
    Custom Elements<br /><br/>
    <custom-elem id="elem1">Element 1</custom-elem>
    <input type="button" id="btn1_add" value="Apply Style"></input>
    <input type="button" id="btn1_remove" value="Remove Style"></input>
    <br /><br />
    <custom-elem id="elem2">Element 2</custom-elem>
    <input type="button" id="btn2_add" value="Apply Style"></input>
    <input type="button" id="btn2_remove" value="Remove Style"></input>
  </body>
</html>

Can somebody tell me, why this happens?

1

There are 1 best solutions below

0
On

According to the issue you've reported on bugs.chromium.org this is in fact a Chrome regression, introduced with a change related to stylesheet mutations in Chrome 85. It did already work correctly pre-85.

Btw, very nice reproducer!

The fix has already been implemented and can be verified using Chrome Canary. The fix will land in Chrome 88, which is supposed to become the stable version on January 19, 2021 (see releases).