Scrollable table with fixed columns and header, with modern CSS

How to make a table with so little JavaScript as possible using modern CSS?

The features I'm trying to have is:

  • fixed column(s) (positioning and width)
  • scrollable in X and Y axis
  • responsive in the X axis (for non fixed width columns).
  • 在这里输入图像描述

    Note: I did see and analyse some of the most popular/seen questions and answers in SO, like here and here for example.

    I know this can be done with JavaScript event handlers for scroll so that a fixed column can be moved down/up to follow the main column. A example of the functionality I am trying to build (but heavily scripted) could be like this. We can also add MutationObserver in the parent element to the table to detect size changes and calculate again the sizes of the table. But this is expensive in performance, and since CSS is also evolving and modernizing I wonder if there are new ways...

    Is there a 2017/2018 solution for this that is only CSS or as little JS overhead as possible?

    I would like to avoid having to implement JavaScript solutions that break so easy like this:

    在这里输入图像描述

    My ideas:

    a) : use position: fixed; in the fixed columns

    Problems:

  • <td> elements height has to be defined or calculated by JavaScript.
  • a scroll event listener is needed and we need to scroll the fixed column programmatically
  • b) : use div(s) to "fake" the left column and have the scrollable content in the table

    Problems:

  • div height has to sync with table rows height
  • HTML semantics lost since fixed "fake" column is not table syntax any more
  • c) : use N tables show only parts of each so I can have HTML markup but keep fixed header/columns.

    Problems:

  • repeated HTML x N
  • have to sync sizes and scroll with JavaScript also

  • Using a scroll event listener and a fixed left column we can use JavaScript like this:

    const firstColumn = [...document.querySelectorAll('table tr > *:first-of-type')];
    const tableContainer = document.querySelector('.table-container');
    tableContainer.addEventListener('scroll', function() {
        const currentScrollPosition = this.scrollTop * -1;
    	firstColumn.forEach(el => el.style.marginTop = currentScrollPosition + 'px');
    });
    .table-container {
        width: 600px;
        height: 300px;
        overflow-x: scroll;
        overflow-y: scroll;
    }
    
    .table-scroller {
        width: 1000px;
    }
    
    table {
        width: 100%;
        margin-left: -13px;
        table-layout: fixed;
        border-collapse: collapse;
        border: none;
    }
    
    table th,
    table td {
        padding: 0.8em;
        border: 1px solid;
        background-color: #eeeeef;
    }
    
    table th {
        background-color: #6699FF;
        font-weight: bold;
    }
    
    table tr {
        height: 60px;
        vertical-align: middle;
    }
    
    table tr > *:first-of-type {
        position: fixed;
        width: 50px;
        margin-left: 13px;
        margin-top: 0;
        height: inherit;
    }
    <div class="table-container">
        <div class="table-scroller">
            <table>
                <tbody>
                    <tr>
                        <td>Edrward 0</td>
                        <td>32</td>
                        <td>London Park no. 0</td>
                        <td>London Park no. 0</td>
                        <td>London Park no. 0</td>
                        <td>London Park no. 0</td>
                        <td>London Park no. 0</td>
                        <td>London Park no. 0</td>
                        <td>London Park no. 0</td>
                        <td>London Park no. 0</td>
                        <td><a href="#">action</a></td>
                    </tr>
                    <tr>
                        <td>Edrward 1</td>
                        <td>32</td>
                        <td>London Park no. 1</td>
                        <td>London Park no. 1</td>
                        <td>London Park no. 1</td>
                        <td>London Park no. 1</td>
                        <td>London Park no. 1</td>
                        <td>London Park no. 1</td>
                        <td>London Park no. 1</td>
                        <td>London Park no. 1</td>
                        <td><a href="#">action</a></td>
                    </tr>
                    <tr>
                        <td>Edrward 2</td>
                        <td>32</td>
                        <td>London Park no. 2</td>
                        <td>London Park no. 2</td>
                        <td>London Park no. 2</td>
                        <td>London Park no. 2</td>
                        <td>London Park no. 2</td>
                        <td>London Park no. 2</td>
                        <td>London Park no. 2</td>
                        <td>London Park no. 2</td>
                        <td><a href="#">action</a></td>
                    </tr>
                    <tr>
                        <td>Edrward 3</td>
                        <td>32</td>
                        <td>London Park no. 3</td>
                        <td>London Park no. 3</td>
                        <td>London Park no. 3</td>
                        <td>London Park no. 3</td>
                        <td>London Park no. 3</td>
                        <td>London Park no. 3</td>
                        <td>London Park no. 3</td>
                        <td>London Park no. 3</td>
                        <td><a href="#">action</a></td>
                    </tr>
                    <tr>
                        <td>Edrward 4</td>
                        <td>32</td>
                        <td>London Park no. 4</td>
                        <td>London Park no. 4</td>
                        <td>London Park no. 4</td>
                        <td>London Park no. 4</td>
                        <td>London Park no. 4</td>
                        <td>London Park no. 4</td>
                        <td>London Park no. 4</td>
                        <td>London Park no. 4</td>
                        <td><a href="#">action</a></td>
                    </tr>
                    <tr>
                        <td>Edrward 5</td>
                        <td>32</td>
                        <td>London Park no. 5</td>
                        <td>London Park no. 5</td>
                        <td>London Park no. 5</td>
                        <td>London Park no. 5</td>
                        <td>London Park no. 5</td>
                        <td>London Park no. 5</td>
                        <td>London Park no. 5</td>
                        <td>London Park no. 5</td>
                        <td><a href="#">action</a></td>
                    </tr>
                    <tr>
                        <td>Edrward 6</td>
                        <td>32</td>
                        <td>London Park no. 6</td>
                        <td>London Park no. 6</td>
                        <td>London Park no. 6</td>
                        <td>London Park no. 6</td>
                        <td>London Park no. 6</td>
                        <td>London Park no. 6</td>
                        <td>London Park no. 6</td>
                        <td>London Park no. 6</td>
                        <td><a href="#">action</a></td>
                    </tr>
                    <tr>
                        <td>Edrward 7</td>
                        <td>32</td>
                        <td>London Park no. 7</td>
                        <td>London Park no. 7</td>
                        <td>London Park no. 7</td>
                        <td>London Park no. 7</td>
                        <td>London Park no. 7</td>
                        <td>London Park no. 7</td>
                        <td>London Park no. 7</td>
                        <td>London Park no. 7</td>
                        <td><a href="#">action</a></td>
                    </tr>
                    <tr>
                        <td>Edrward 8</td>
                        <td>32</td>
                        <td>London Park no. 8</td>
                        <td>London Park no. 8</td>
                        <td>London Park no. 8</td>
                        <td>London Park no. 8</td>
                        <td>London Park no. 8</td>
                        <td>London Park no. 8</td>
                        <td>London Park no. 8</td>
                        <td>London Park no. 8</td>
                        <td><a href="#">action</a></td>
                    </tr>
                    <tr>
                        <td>Edrward 9</td>
                        <td>32</td>
                        <td>London Park no. 9</td>
                        <td>London Park no. 9</td>
                        <td>London Park no. 9</td>
                        <td>London Park no. 9</td>
                        <td>London Park no. 9</td>
                        <td>London Park no. 9</td>
                        <td>London Park no. 9</td>
                        <td>London Park no. 9</td>
                        <td><a href="#">action</a></td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>

    Maybe you could try to use the recent position:sticky to achieve it. Or, at least, to start the aproach with less javascript.

    div{
      overflow:auto;
      width:100%;
      height:200px;
    }
    td,
    th {
      border: 1px solid #000;
      width: 100px;
    }
    th {background-color:red;}
    
    table {
      table-layout: fixed;
      width:100%;
    }
    td:first-child, th:first-child {
      position:sticky;
      left:0;
      z-index:1;
      background-color:grey;
    }
    td:last-child, th:last-child {
      position:sticky;
      right:0;
      z-index:1;
      background-color:blue;
    }
    thead tr th {
      position:sticky;
      top:0;
    }
    th:first-child, th:last-child {z-index:2;background-color:red;}
    <div>
      <table>
        <thead>
          <tr>
            <th>&nbsp;&nbsp;&nbsp;</th>
            <th>&nbsp;&nbsp;&nbsp;</th>
            <th>&nbsp;&nbsp;&nbsp;</th>
            <th>&nbsp;&nbsp;&nbsp;</th>
            <th>&nbsp;&nbsp;&nbsp;</th>
            <th>&nbsp;&nbsp;&nbsp;</th>
            <th>&nbsp;&nbsp;&nbsp;</th>
            <th>&nbsp;&nbsp;&nbsp;</th>
            <th>&nbsp;&nbsp;&nbsp;</th>
            <th>&nbsp;&nbsp;&nbsp;</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
          </tr>
          <tr>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
          </tr>
          <tr>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
          </tr>
          <tr>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
          </tr>
          <tr>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
          </tr>
          <tr>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
          </tr>
          <tr>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
          </tr>
          <tr>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
          </tr>
          <tr>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
            <td>&nbsp;&nbsp;&nbsp;</td>
          </tr>
        </tbody>
      </table>
    </div>
    链接地址: http://www.djcxy.com/p/40604.html

    上一篇: JavaScript的

    下一篇: 具有固定列和标题的可滚动表格,具有现代CSS