为什么我的 Web 组件 CSS 不显示?我没有使用 shadowDOM

Why does my Web Component CSS not show? I am not using shadowDOM

我有一个未使用 shadowDOM 的原生 V1 组件,所以我将 CSS 放在 <head> 中。但是当其他人使用我的组件时,我的 CSS 不再有效。

只有当他们的组件确实使用 shadowDOM 时才会发生这种情况。

我的组件的示例代码:

class MyEl extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.innerHTML = `<div class="spaced"><button class="happy-btn">I'm Happy</button></div>
    <div class="spaced"><button class="sad-btn">I'm Sad</button></div>`;
  }
}

// Define our web component
customElements.define('my-el', MyEl);
button {
  padding: 8px 20px;
}

.happy-btn {
  background-color: pink;
}

.sad-btn {
  background-color: #007;
  color: white;
}
<my-el></my-el>

我的 CSS 被加载到 <head> 标签中,因为我没有使用 shadowDOM。但是一旦外部元素将我包含在他们的 shadowDOM 中,事情就会分崩离析。

如果您正在创建一个不使用 ShadowDOM 的组件,您可能仍需要将 CSS 添加到 shadowRoot 中。如果其他人将您的组件放入他们的 shadowDOM,那么您必须将您的 CSS 添加到他们的 shadowRoot。您可以使用以下代码执行此操作:

const myStyle = document.createElement('style');
myStyle.setAttribute('component', 'my-el');
myStyle.textContent = `    button {
  padding: 8px 20px;
}
.happy-btn {
  background-color: pink;
}

.sad-btn {
  background-color: #007;
  color: white;
}`;

function addCss(el, selector, styleEl) {
  // Check to see if we have been placed into a shadow root.
  // If we have then add our CSS into that shadow root.
  let doc;
  try {
    doc = el.getRootNode();
    if (doc === document) {
      doc = document.head;
    }
  }
  catch(_ex) { doc = document.head; } // Shadow DOM isn't supported.

  if (!doc.querySelector(selector)) {
    doc.appendChild(styleEl.cloneNode(true));
  }
}

class MyEl extends HTMLElement {
  constructor() {
    super();
    addCss(this, 'style[component="my-el"]', myStyle);
  }
  connectedCallback() {
    this.innerHTML = `<div class="spaced"><button class="happy-btn">I'm Happy</button></div>
    <div class="spaced"><button class="sad-btn">I'm Sad</button></div>`;
  }
}
customElements.define('my-el', MyEl);

class TheirEl extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({mode:'open'});
    this.shadowRoot.innerHTML = `<hr/><my-el></my-el><hr/><my-el></my-el><hr/>`;
  }
}
customElements.define('their-el', TheirEl);
<their-el></their-el>

函数 addCss 会将您的 CSS 放入正确的 shadowRoot 中,如果没有 shadowRoot 则放入 document.head

您必须在构造函数中调用 addCss 才能将 CSS 放置在正确的位置。只要您有一个唯一的选择器来标识您的 <style> 标签,此例程还将确保您不会添加它两次。

在我的代码中,您看到 <style> 标记添加了一个名为 component 的属性,其值为组件名称。就我而言 component="my-el".

然后我使用选择器 'style[component="my-el"]' 查看该标签是否已经在 shadowRoot 中,或者如果没有 shadowRoot 则 document.head ,如果不存在则只添加样式。

您不能仅仅因为您没有使用它就假设您的组件不会在影子中 DOM。使用上面的示例来保护自己。

旁注

If you are using shadow DOM then this problem goes away since your have to place your CSS into your own shadowRoot.