Skip to content

[cssom] Need to agree on when LinkStyle.sheet gets updated in shadow trees. #3096

@emilio

Description

@emilio

Since it's observable via cssRules and all that stuff.

In Gecko, when a shadow host is unbound, we also disconnect the ShadowRoot children. This has side effects, such as losing (only temporarily) the sheet pointer, and losing the disabled state.

I was going to fix this in Gecko, when to my surprise Chrome (which is the only other implementor of ShadowRoot.styleSheets doesn't keep the stylesheets around in disconnected subtrees.

We should agree on when should they be kept.

Test-case (sorry, pretty messy):

<!doctype html>
<div id="host"></div>
<script>
  let host = document.querySelector("#host");
  host.attachShadow({ mode: "open" }).innerHTML = `<style>* { color: red }</style><span>Should not be red</span>`;

  console.log("host.shadowRoot.styleSheets", host.shadowRoot.styleSheets);
  console.log("style.sheet", host.shadowRoot.querySelector('style').sheet);

  let sheet = host.shadowRoot.styleSheets[0];
  console.log("host.shadowRoot.styleSheets[0]", sheet);
  sheet.disabled = true;

  // assert_equals(getComputedStyle(host.shadowRoot.querySelector('span')).color, "rgb(0, 0, 0)");
  document.body.offsetTop;

  host.remove();

  console.log("host.shadowRoot.styleSheets (after removal)", host.shadowRoot.styleSheets);
  console.log("style.sheet (after removal)", host.shadowRoot.querySelector('style').sheet);
  sheet = host.shadowRoot.styleSheets[0];
  console.log("host.shadowRoot.styleSheets[0] (after removal)", sheet);
  console.log("host.shadowRoot.styleSheets[0].disabled (after removal)", sheet ? sheet.disabled : "(no sheet)");

  document.body.offsetTop;
  document.body.appendChild(host);

  document.body.offsetTop;
  let host2 = document.createElement('div');
  host2.attachShadow({ mode: "open" }).innerHTML = `<style>* { color: red }</style><span>Should not be red</span>`;
  console.log("host2.shadowRoot.styleSheets", host2.shadowRoot.styleSheets);
  console.log("style.sheet", host2.shadowRoot.querySelector('style').sheet);
  sheet = host2.shadowRoot.styleSheets[0];
  console.log("host2.shadowRoot.styleSheets[0]", sheet);
</script>

Or online at https://crisal.io/tmp/disabled-shadow.html.

And to be clear I'm fine speccing and implementing the Blink behavior, if we decide that accessing stylesheets in disconnected shadow roots is not worth the churn.

cc @lilles @tabatkins @rniwa

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions