Веб-компонент HTML не использует стиль теневой DOM
Я создал обычный веб-компонент или HTML-элемент. Он просто отображает две ссылки.
Чтобы инкапсулировать вещь, я использую теневой DOM. Однако, похоже, он не инкапсулирован. В дереве DOM он находится внутри # shadow-root, что хорошо.
Почему веб-компонент использует глобальный стиль вместо стиля, который я предоставил в шаблоне для моего веб-компонента?
Текст красный, и я ожидал, что он будет зеленым.
class MyEl extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: "open" });
}
connectedCallback() {
const template = `
<style>
a {
color: green;
}
</style>
<slot></slot>`;
this.shadow.innerHTML = template;
}
}
window.customElements.define("my-el", MyEl);
a {
color: red
}
<my-el>
<a href="example.com">Item1</a>
<a href="example.com">Item2</a>
</my-el>
Ответы
Хотя на этот вопрос уже есть принятый ответ, перемещение дочерних элементов слота в shadowRoot нежелательно для большинства случаев использования.
Вероятно, вы захотите использовать ::slotted()
селектор.
Просто имейте в виду, что стили, применяемые к дочерним элементам слота через ::slotted()
селектор, действуют только как стили «по умолчанию» и могут быть отменены с помощью стилей в облегченной модели DOM.
Например, проверьте эту отредактированную версию вашего фрагмента:
Как видите, на этот раз my-el
пытается применить и цвет, и стиль оформления текста к дочерним <a>
элементам anchor ( ) в любом из своих слотов.
Однако в light dom у нас есть a.special
селектор, который переопределяет цвет, поэтому <a class="special">
он будет красным, а не зеленым.
class MyEl extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: "open" });
}
connectedCallback() {
const template = `
<style>
::slotted(a) {
color: green;
text-decoration: none;
}
</style>
<slot></slot>`;
this.shadow.innerHTML = template;
}
}
window.customElements.define("my-el", MyEl);
a.special {
color: red
}
<my-el>
<a href="example.com">Item1</a>
<a class="special" href="example.com">Item2</a>
</my-el>
Полное, подробное объяснение находится в: :: Селектор CSS со слотами для вложенных потомков в слот shadowDOM.
TL; DR
Ваши ссылки находятся в lightDOM и, таким образом, стилизованы под его DOM (в вашем коде - документ DOM).
Перемещение узлов из lightDOM в shadowDOM - одно из «решений»; но тогда вы не используете слоты.
К вашему сведению, ваш код можно сжать до:
class MyEl extends HTMLElement {
constructor() {
super().attachShadow({ mode: "open" })
.innerHTML = `<style>a{color:green}</style><slot></slot>`;
}
}
window.customElements.define("my-el", MyEl);
Больше ответов, связанных с SLOT, можно найти с помощью StackOverflow Search: Custom Elements SLOTs
обратите внимание на эту строку, вы должны перемещать / копировать элементы в тень, например, с помощью:
this.shadow.innerHTML = this.innerHTML + template;
Я добавил это, чтобы продемонстрировать, что к элементам shadow dom будет применяться только встроенный стиль ... поэтому скопированные ссылки в SD используют ваш стиль :)
так красный будет GLOBAL
, зеленый будет SHADOW
элементами

class MyEl extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.shadow = this.attachShadow({ mode: "open" });
const template = `
<style>
a {
color: green;
}
</style>
<slot></slot>`;
this.shadow.innerHTML = this.innerHTML + template;
}
}
window.customElements.define("my-el", MyEl);
a {
color: red
}
<my-el>
<a href="example.com">Item1</a>
<a href="example.com">Item2</a>
</my-el>