简体   繁体   English

带有固定列和标题的可滚动表格,带有现代 CSS

[英]Scrollable table with fixed columns and header, with modern CSS

How to make a table with so little JavaScript as possible using modern CSS?如何使用现代 CSS 用尽可能少的 JavaScript 制作表格?

The features I'm trying to have is:我试图拥有的功能是:

  • fixed column(s) (positioning and width)固定列(定位和宽度)
  • scrollable in X and Y axis可在 X 和 Y 轴上滚动
  • responsive in the X axis (for non fixed width columns).在 X 轴上响应(对于非固定宽度的列)。

在此处输入图片说明

Note: I did see and analyse some of the most popular/seen questions and answers in SO, like here and here for example.注意:我确实看到并分析了 SO 中一些最受欢迎/看到的问题和答案,例如这里这里

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.我知道这可以通过用于滚动的 JavaScript 事件处理程序来完成,以便固定列可以向下/向上移动以跟随主列。 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.我们还可以在表的父元素中添加MutationObserver来检测大小变化并再次计算表的大小。 But this is expensive in performance, and since CSS is also evolving and modernizing I wonder if there are new ways...但这在性能上很昂贵,而且由于 CSS 也在不断发展和现代化,我想知道是否有新的方法......

Is there a 2017/2018 solution for this that is only CSS or as little JS overhead as possible?是否有一个 2017/2018 解决方案,它只有 CSS 或尽可能少的 JS 开销?

I would like to avoid having to implement JavaScript solutions that break so easy like this:我想避免必须实现像这样容易崩溃的 JavaScript 解决方案:

在此处输入图片说明

My ideas:我的想法:

a) : use position: fixed; a) :使用position: fixed; in the fixed columns在固定列中

Problems:问题:

  • <td> elements height has to be defined or calculated by JavaScript. <td>元素的高度必须由 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 b) : 使用 div(s) 来“伪造”左列并在表格中包含可滚动的内容

Problems:问题:

  • div height has to sync with table rows height div 高度必须与表格行高度同步
  • HTML semantics lost since fixed "fake" column is not table syntax any more由于固定的“假”列不再是表格语法,因此 HTML 语义丢失

c) : use N tables show only parts of each so I can have HTML markup but keep fixed header/columns. c) :使用N 个表格只显示每个表格的一部分,这样我就可以使用 HTML 标记但保留固定的标题/列。

Problems:问题:

  • repeated HTML x N重复的 HTML x N
  • have to sync sizes and scroll with JavaScript also还必须同步大小并使用 JavaScript 滚动

Using a scroll event listener and a fixed left column we can use JavaScript like this:使用滚动事件侦听器和固定的左列,我们可以像这样使用 JavaScript:

 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>

But can I do this without JavaScript?但是我可以在没有 JavaScript 的情况下做到这一点吗?


About the possible duplicate suggestion:关于可能的重复建议:

That possible duplicate is mentioned in my question and it does not have what I'm looking for.我的问题中提到了可能的重复项,但它没有我正在寻找的内容。 That question asks for "just a single left column to be frozen" - the scope of this one is more broad, its relates to fixed header, fixed columns and scrollable body.这个问题要求“只冻结一个左列” - 这个问题的范围更广泛,它与固定标题、固定列和可滚动正文有关。
The other question and the accepted answer are from 2009!另一个问题和接受的答案来自 2009 年! I think this topic, with my specific scope and examples is worth being revisited.我认为这个话题,以及我的具体范围和例子值得重新审视。 Also: my "JS solution" is just a example how JS can break, I'm looking for modern CSS techniques for doing just that.另外:我的“JS 解决方案”只是 JS 如何破坏的一个例子,我正在寻找现代 CSS 技术来做到这一点。

Maybe you could try to use the recent position:sticky to achieve it.也许您可以尝试使用最近的position:sticky来实现它。 Or, at least, to start the aproach with less javascript.或者,至少,以较少的 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>

Just look at my code with a fixed header and fix the first column.只需查看带有固定标题的代码并修复第一列即可。

    <style type="text/css">
    .table {
          font-family: arial, sans-serif;
  border-collapse: collapse;
}

.th {
  width: 126px;
  height: 56px;
  padding: 0px 16px;
  text-align: left;
  background-color: #fafafa;
}

.td {
  width: 118px;
  min-width: 118px;
  max-width: 118px;
  height: 56px;
  max-height: 56px;
  overflow: hidden;
  text-align: center;
  border-bottom: 2px solid #dddddd;
}
.pink_color {
  background-color: pink;
}

.table_wrapper {
  position: relative;
}
.table_scroll {
  height: 73vh;
  overflow: auto;
}
.table_wrapper table {
  width: 100%;
}

.table_wrapper table thead th .text {
  position: absolute;
  z-index: 2;
}
.tableFixHead
{ 
  overflow: auto; height: 63vh; 
}
.tableFixHead thead th 
{ 
  position: sticky; top: 0; z-index: 1; 
}


@media only screen and (min-width: 1440px) {
  .table_scroll {
    height: 77vh;
    overflow: auto;
  }
}
</style>

<div style="padding-top: 16px;">
    <div class="table_wrapper">
        <div class="tableFixHead">
            <table class="table">
                <thead>
                  <th style="position: sticky; left: 0; z-index: 3;" class="text th"></th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                  <th class="text th">1</th>
                </thead>
                <tr>
                  <td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                </tr>
                <tr>
                  <td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
                  <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                </tr>
                <tr>
                  <td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
                  <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                </tr><tr>
                  <td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
                  <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                </tr><tr>
                  <td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
                  <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                </tr><tr>
                  <td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
                  <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                </tr><tr>
                  <td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
                  <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                    <td class="td">test1</td>
                </tr>
            </table>
        </div>
    </div>
</div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM