Почему мой веб-компонент CSS не отображается? Я не использую shadowDOM

У меня есть компонент Native V1, который не использует shadowDOM, поэтому я помещаю свой 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, все рушится.

1 ответ

Решение

Если вы создаете компонент, который НЕ использует 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 или в document.head если нет shadowRoot.

Вы должны позвонить addCss в вашем конструкторе, чтобы разместить CSS в правильном месте. Эта процедура также гарантирует, что вы не добавите ее дважды, если у вас есть уникальный селектор для идентификации вашего <style> тег.

В моем вы видите <style> тег добавляет атрибут с именем component со значением имени компонента. В моем случае component="my-el",

Затем я использую селектор 'style [component = "my-el"] ", чтобы посмотреть, есть ли этот тег уже в shadowRoot, или document.head если не существует shadowRoot, и добавляйте стили только в том случае, если он еще не существует.

Вы не можете предполагать, что ваш компонент не будет находиться в теневой DOM только потому, что вы его не используете. Используйте пример выше, чтобы защитить себя.

Примечание

Если вы используете shadow DOM, то эта проблема исчезнет, ​​так как вам придется поместить свой CSS в ваш собственный shadowRoot.

Другие вопросы по тегам