Взаимодействие между CSS grid и смешанным ShadowDOM / LightDOM

#javascript #html #css-grid #shadow-dom #custom-element

#javascript #HTML #css-grid #shadow-dom #пользовательский элемент

Вопрос:

В настоящее время я экспериментирую со слотами в пользовательских элементах.

Посмотрите на этот простой пример:

 customElements.define('x-y', class extends HTMLElement {
  constructor() {
    super();
    let template = document.createElement('template');
    template.innerHTML = `<style>
    :host { display: block; align-self: normal; }
    div {
      background-color: #666;
      color: white;
      padding: 5px;
    }
  </style>
  <div>affected by styles from ShadowDOM</div>
  <slot name="content"></slot>`;

    const shadowRoot = this.attachShadow({
      mode: 'open'
    }).appendChild(template.content.cloneNode(true));
  }
}) 
 body {
  border: 2px dashed magenta;
  display: grid;
  height: 100vh;
  grid-template-rows: minmax(0, 1fr);
  margin: 0;
}

* {
  box-sizing: border-box;
}

x-y>div {
  background-color: #f0f0f0;
  padding: 5px;
}

.inner-grid {
  display: grid;
  grid-template-rows: 1fr 2fr;
  height: 100%;
  overflow: auto;
} 
 <x-y class="inner-grid">
  <div slot="content">not affected by styles from ShadowDOM</div>
</x-y> 

Как мы можем видеть, определение сетки для .inner-grid , хотя и определено в CSS страницы, влияет на отображение содержимого ShadowDOM.

Это, хотя и удобно, стало неожиданным, поскольку внешний CSS не должен влиять на внутренние компоненты веб-компонента (исключениями являются унаследованные свойства и пользовательские свойства).

Второе ожидание, которое у меня было — которое также нарушено, — заключается в том, что контейнер сетки делает так, чтобы его прямые дочерние элементы становились ячейками сетки, к которым применяются определения шаблонов сетки, если таковые имеются. Как элемент внутри ShadowDOM может быть таким прямым дочерним элементом?

Это структура в инспекторе элементов Chrome:

Структура DOM

Вопрос: Может ли кто-нибудь пролить некоторый свет на то, как именно это работает? Как CSS grid взаимодействует со смешанным контентом shadow DOM / light DOM? Пожалуйста, добавьте ссылку, если таковая имеется.

Ответ №1:

Я попытался понять ваш вопрос, используя свой собственный код.

Итак, я поместил ваш .inner-grid элемент в сетку из 3 столбцов <game-board>

Ваш вопрос # 1

Как мы можем видеть, определение сетки для .inner-grid, хотя и определено в CSS страницы, влияет на отображение содержимого ShadowDOM.

Как вы видите, это влияет на содержимое ShadowDOM «?

Красный фон — это то, что вы имеете в виду?

Теневой корень считается элементом, занимающим много места, поэтому равен 1fr

Затем display:grid; grid-template-rows:repeat( 3 , 1fr ); на контейнере увеличится высота контейнера в 3 раза (таким образом, уменьшится его теневой корень).

Ваш вопрос # 2

Второе ожидание, которое у меня было — которое также нарушено, — заключается в том, что контейнер сетки делает так, чтобы его прямые дочерние элементы становились ячейками сетки, к которым применяются определения шаблонов сетки, если таковые имеются. Как элемент внутри ShadowDOM может быть таким прямым дочерним элементом?

Слоты (или фактически разделенное содержимое / «распределенные узлы«) являются прямыми дочерними элементами в сетке

     <slot name="A1"></slot>  <slot name="A2"></slot>            <slot></slot>
    <slot name="B1"></slot>  <span>gridded in shadowDOM</span>  <slot name="B2"></slot>
 

работа с сеткой 3×2

Примечание:

  • В СЛОТЕ A2 ничего нет, он не заполняет область сетки
  • 2 элемента из LightDOM переходят в слот по умолчанию <slot></slot> и заполняют 2 области сетки.
 <template id=GAME-BOARD>
  <style description="style shadowDOM">
    div {
      background: lightgreen;
      display: grid; grid-template-columns: repeat(3, 1fr)  }
    ::slotted(*) { border: 3px dashed green }
  </style>
  <div>
    <slot name="A1"></slot> <slot name="A2"></slot>           <slot></slot>
    <slot name="B1"></slot> <span>gridded in shadowDOM</span> <slot name="B2"></slot>
  </div>
</template>
<style description="lightDOM game-pieces">
 game-board{ background:red; display:grid; grid-template-rows:repeat(3,1fr)}
 game-piece{ background:lightblue }
</style>
<game-board>
  <game-piece>to default slot!</game-piece>
  <game-piece slot="A1"></game-piece>
  <game-piece slot="B2"></game-piece>
  <div>GRIDDED from ligthDOM to default slot</div>
</game-board>
<script>
  customElements.define('game-board', class extends HTMLElement {
    constructor() {
      super().attachShadow({mode: 'open'})
             .append(document.getElementById(this.nodeName).content.cloneNode(true));
    }})
  customElements.define('game-piece', class extends HTMLElement {
    connectedCallback() {
      this.innerHTML = this.getAttribute("slot") || "NO SLOT";
    }})
</script> 

Если вы хотите создать шахматную доску, вам нужно по умолчанию поместить элемент в каждый из 64 слотов. Они также необходимы для захвата движений перетаскивания / касания.

Тогда проще работать с named grid-template-areas (в ShadowDOM).

И позиционировать с помощью (64) CSS-селекторов:

  ::slotted([slot="A5"]){ grid-area:A5 }
 

И используйте значение по умолчанию <slot></slot> для захвата фигур, не расположенных на доске.

Я сделал шахматную доску с компонентами 2 года назад: https://chessmeister.github.io (не используя все, что я знаю сейчас)