Как создать html <table>, который имеет фиксированный заголовок ** и ** закрепленные столбцы, используя в основном CSS

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

Проблема, с которой я сталкиваюсь, заключается в том, что при прокрутке по горизонтали столбцы в заголовке появляются сзади, а не сверху. Браузер определяет, какие элементы DOM должны быть сверху после выполнения преобразования. Что я могу сделать, чтобы это контролировать? (да, я пробовал z-index)

Demo

(function() {
  var app = angular.module("soDemo", []);
  app.controller("soDemoController", SoDemoController);

  SoDemoController.$inject = ['$scope', '$document'];

  function SoDemoController($scope, $document) {
    var vm = {
      data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    };

    $scope.vm = vm;
    $('.table-container').on('scroll', onScroll);

    return;

    /////////// IMPLEMENATION ////////
    function onScroll() {
      var translate = "translate(0," + this.scrollTop + "px)";
      $("table thead th:not(.pinned)").css('transform', translate);

      translate = "translate(" + this.scrollLeft + "px,0)";
      $("table tbody .pinned").css('transform', translate);

      translate = "translate(" + this.scrollLeft + "px," + this.scrollTop + "px)";
      $("table thead th.pinned").css('transform', translate);
    }
  }
})();
.table-container {
  overflow: auto;
  height: 200px;
  width: 300px
}

table {
  table-layout: fixed;
  border-spacing: 0;
}

td {
  padding: 3px;
  white-space: nowrap;
  border-right: 1px solid #ccc;
}

th {
  background: #999;
}

th.pinned {
  background: #ccc;
}

td.pinned {
  background: #eee;
}

input {
  margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>

<div class="sample" ng-app="soDemo" ng-controller="soDemoController">
  <p>When you scroll horizontally, the header row scrolls on top of col0 and col1 instead of behind it.</p>
  <p>When you scroll vertically, the tbody cells render over top of Col 0 and Col 1 headers instead of behind it</p>
  <div class="table-container">
    <table>
      <thead>
        <tr>
          <th class="pinned">Col 0</th>
          <th class="pinned">Col 1</th>
          <th>Col 2</th>
          <th>Col 3</th>
          <th>Col 4</th>
          <th>Col 5</th>
          <th>Col 6</th>
          <th>Col 7</th>
          <th>Col 8</th>
          <th>Col 9</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="item in vm.data">
          <td class="pinned">Data {{item}}</td>
          <td class="pinned">Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

Ответ 1

Я думаю, что это проблема z-index.

Благодаря @sascha10000 они заставили меня задуматься о том, чего не хватает. Если вы добавите position: relative в класс th.pinned в свой css, а также добавьте положительный z-index. (т.е. z-index:20). Кажется, что это работает.

(function() {
  var app = angular.module("soDemo", []);
  app.controller("soDemoController", SoDemoController);

  SoDemoController.$inject = ['$scope', '$document'];

  function SoDemoController($scope, $document) {
    var vm = {
      data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    };

    $scope.vm = vm;
    $('.table-container').on('scroll', onScroll);

    return;

    /////////// IMPLEMENATION ////////
    function onScroll() {
      var translate = "translate(0," + this.scrollTop + "px)";
      $("table thead th:not(.pinned)").css('transform', translate);

      translate = "translate(" + this.scrollLeft + "px,0)";
      $("table tbody .pinned").css('transform', translate);

      translate = "translate(" + this.scrollLeft + "px," + this.scrollTop + "px)";
      $("table thead th.pinned").css('transform', translate);
    }
  }
})();
.table-container {
  overflow: auto;
  height: 200px;
  width: 300px
}

table {
  table-layout: fixed;
  border-width: 0;
  border-spacing: 0;
}

td {
  padding: 3px;
  white-space: nowrap;
  border-right: 1px solid #ccc;
}

th {
  background: #999;
}

th.pinned {
  position: relative; /**** <===  added this ****/
  z-index: 20;        /**** <===  added this ****/
  background: #ccc;
}

td.pinned {
  background: #eee;
}

input {
  margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>

<div class="sample" ng-app="soDemo" ng-controller="soDemoController">
  <p>When you scroll horizontally, the header row scrolls on top of col0 and col1 instead of behind it.</p>
  <p>When you scroll vertically, the tbody cells render over top of Col 0 and Col 1 headers instead of behind it</p>
  <div class="table-container">
    <table>
      <thead>
        <tr>
          <th class="pinned">Col 0</th>
          <th class="pinned">Col 1</th>
          <th>Col 2</th>
          <th>Col 3</th>
          <th>Col 4</th>
          <th>Col 5</th>
          <th>Col 6</th>
          <th>Col 7</th>
          <th>Col 8</th>
          <th>Col 9</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="item in vm.data">
          <td class="pinned">Data {{item}}</td>
          <td class="pinned">Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
          <td>Data {{item}}</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

Ответ 2

Это характер работы table, который вы можете эмулировать table для достижения этой функциональности, но я не знаю, как использовать table, потому что table имеет тенденцию игнорировать значения z-индекса.

Ответ 3

Вы проверили position: sticky? Я абсолютно уверен, что это именно то, что вы ищете. Вам нужно будет установить z-index в строке/столбце, чтобы держать его выше остальных.

позиция: липкая на MDN