Липкие HTML-элементы во вложенных окнах прокрутки отображаются некорректно

#javascript #html #css

#javascript #HTML #css

Вопрос:

В следующем сценарии…

JSFiddle

… если вы немного прокрутите внешнюю таблицу, вы увидите, что липкие заголовки таблиц во внутреннем контейнере прокрутки фактически отображаются ПОВЕРХ заголовка внешнего контейнера прокрутки.

Разве эти два набора заголовков не должны существовать в отдельных контекстах стекирования?

Есть ли какое-либо обходное решение для этого, помимо простого жесткого кодирования значений z-индекса? Это всего лишь макет того, что генерируется динамически, поэтому мне пришлось бы установить много настроек, чтобы динамически вычислять правильные значения z-index для использования на каждом уровне относительно всех других уровней.

Здесь не используется фреймворк JavaScript, только TypeScript и require.

HTML-код:

 <div class="scroll-container">
  <table class="outer-table">
    <thead>
      <tr>
        <th>Outer Column 1</th>
        <th>Outer Column 2</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td colspan="2">
          <div class="scroll-container">
            <table class="inner-table">
              <thead>
                <tr>
                  <th>Inner Column 1</th>
                  <th>Inner Column 2</th>
                  <th>Inner Column 3</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
                <tr>
                  <td>Inner Value 1</td>
                  <td>Inner Value 2</td>
                  <td>Inner Value 3</td>
                </tr>
              </tbody>
            </table>
          </div>
        </td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
      <tr>
        <td>Outer Value 1</td>
        <td>Outer Value 2</td>
      </tr>
    </tbody>
  </table>
</div>
  

CSS:

 div.scroll-container {
  max-height: 20em;
  overflow-y: scroll;
}

table.outer-table div.scroll-container {
  max-height: 10em;
}

table {
  border: 1px solid black;
  margin: 1em;
}

td, th {
  border: 1px solid blue;
}

th {
  position: sticky;
  top: 0;
  height: 2em;
}

table.outer-table th {
  background: tan;
}

table.inner-table th {
  background: gray;
}
  

Ответ №1:

У вас есть только один класс, работающий для обеих таблиц, поэтому не делается различий в том, какой из них отображается сверху или под другим. Вероятно, у вас не будет другого выбора, кроме как использовать два отдельных класса и добавить z-индекс для каждого. Например — использование одного и того же полного определения класса для каждой таблицы:

 table.outer-table thead tr th {
  position:sticky;
  top:0px;
  height:2em;
  z-index:99;
}

table.inner-table thead tr th {
  position:sticky;
  top:0px;
  height:2em;
  z-index:98;
}
  

Я протестировал это на вашей странице JSFiddle, и, похоже, он делал то, что вы хотели, так что, похоже, здесь важен z-индекс. Если вложенность таблиц может быть обширной, класс может настроить на них таргетинг, используя что-то вроде:

 table {z-index:99}
table > table {z-index:98}
table > table > table {z-index:97}
  

ie — таблица, таблица внутри таблицы и таблица внутри таблицы внутри таблицы.

Комментарии:

1. Каким бы хакерским это ни казалось, мне определенно нравится это CSS-решение, а не решение на основе JS. Это хорошая идея, спасибо.

2. css проще, потому что вы можете указать столько вложенных таблиц, сколько захотите — если нет таблицы, вложенной так глубоко, она просто не применяется.