首页 > 解决方案 > 固定标题 HTML 表格上的额外水平滚动条?

问题描述

我有一些包含很多列的 HTML 表格。我目前正在尝试升级这些表以具有固定的标题,所以我在网上浏览了一些示例,这些示例说要固定表布局,thead 和 tbody 块,限制 tbody 的高度,并在 tbody 上设置溢出-y。一切正常,我的数据滚动,而标题保持不变。

但是,每当我有足够的列宽度溢出视口时,我就会得到两个我没有要求的水平滚动条。我没有在任何地方设置溢出或溢出-x,但我得到了两个水平滚动条——一个只用于 tbody,一个用于整个表格。使用 tbody 滚动显示所有数据,但将标题保留在适当的位置,因此它们不会与数据对齐,并且滚动 table one 不允许您查看原始视口之外的数据,因为有一个垂直滚动条视口的右边缘最初是。

我实际上使用的是旧版本的 Vuetify(不,我无法升级),但我已经缩小了很多范围,并在这里用一个简单的 HTML/CSS-only 示例重现了这个问题。任何人都可以向我解释水平滚动条的来源吗?我确实想要一个水平滚动条,可能是表格的那个,但我希望它同时滚动数据和标题。大概摆脱 tbody 滚动条会做到这一点,但我没有在任何地方定义它,所以我不知道如何删除它。事实上,检查员根本没有在任何地方显示溢出-x!我尝试将 overflow-x 添加到各种元素以尝试强制滚动条,以便这些自动滚动条不需要显示,但到目前为止还没有运气。

在此先感谢您的任何建议!

示例 CSS:

table {
  table-layout: fixed;
  width: 100%;
}

thead tr, tbody {
  display: block;
}

tbody {
  height: 300px;
  overflow-y: auto;
}

th, td {
  width: 100px;
  min-width: 100px;
}

示例 HTML:

<html>
  <div style="max-width: 500px; overflow-y: auto;">
    <table>
      <thead>
        <tr>
          <th>Column 1</th>
          <th>Column 2</th>
          <th>Column 3</th>
          <th>Column 4</th>
          <th>Column 5</th>
          <th>Column 6</th>
          <th>Column 7</th>
          <th>Column 8</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Data1</td>
          <td>Data2</td>
          <td>Data3</td>
          <td>Data4</td>
          <td>Data5</td>
          <td>Data6</td>
          <td>Data7</td>
          <td>Data8</td>
        <tr>
        <tr>
          <td>Data1</td>
          <td>Data2</td>
          <td>Data3</td>
          <td>Data4</td>
          <td>Data5</td>
          <td>Data6</td>
          <td>Data7</td>
          <td>Data8</td>
        <tr>
        <!-- more rows to make it scroll vertically -->
      </tbody>
    </table>
  </div>
</html>

标签: htmlcss

解决方案


您正在谈论的滚动条正在添加到tbody元素中。通过tbody变成一个块,overscroll:auto默认情况下会被添加,即使你只包含overflow-y在你的 CSS 中:

thead tr, tbody {
  display: block;
}
tbody {
  height: 300px;
  overflow-y: auto;
}

部分解决方案(在没有水平溢出时有效

添加overflow-y:hiddentbody将删除第二个水平滚动条,这在没有水平溢出时有效。但是,如果有,垂直滚动条会“卡在”位于最大宽度的列上并与 tbody 一起滚动,如您在此处看到的:

table {
  table-layout: fixed;
  width: 100%;
}

thead tr, tbody {
  display: block;
}

tbody {
  height: 300px;
  overflow-y: auto;
  overflow-x: hidden;
}

th, td {
  width: 100px;
  min-width: 100px;
}
<html>
  <div style="max-width: 500px; overflow-y: auto;">
    <table>
      <thead>
        <tr>
          <th>Column 1</th>
          <th>Column 2</th>
          <th>Column 3</th>
          <th>Column 4</th>
          <th>Column 5</th>
          <th>Column 6</th>
          <th>Column 7</th>
          <th>Column 8</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
      </tbody>
    </table>
  </div>
</html>

最大的问题是使tbody滚动独立于thead垂直方向(我们想要这样做,因为我们想要保留标题)也会阻止它在水平滚动上工作(我们不会这样做,因为标题不会随 tbody 移动)。

水平和垂直溢出的纯 CSS 解决方案(部分浏览器支持

当表格的其余部分在其后面向上滚动时,使用position:sticky标题行将使其保持在表格的顶部:

th {
   position: sticky;
   top: 0;
   background: #FFF; /* otherwise we can see the scrolling data behind it */
}
table {
  /* prevent the th scrolling up by the default border size before "sticking" */
  border-collapse: collapse;  
}

然而,这只有部分浏览器支持。请注意,它仅适用于th(而不是theador tr)在 Chrome、FF 和其他中。

工作示例(或不,取决于您的浏览器!):

table {
  table-layout: fixed;
  width: 100%;
  /* the prevents the th scrolling up by the default border size before "sticking" */
  border-collapse: collapse;
}

th, td {
  width: 100px;
  min-width: 100px;
}

th {
  position: sticky;
  top: 0;
  background: #FFF;
}
<html>
  <p>This is some content to show the effect of the sticky header and top:0 on the rest of the page </p>
  <div style="max-width: 500px; height:200px; overflow: auto;">
    <table>
      <thead>
        <tr>
          <th>Column 1</th>
          <th>Column 2</th>
          <th>Column 3</th>
          <th>Column 4</th>
          <th>Column 5</th>
          <th>Column 6</th>
          <th>Column 7</th>
          <th>Column 8</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
      </tbody>
    </table>
  </div>
  <p>This is some content to show the effect of the sticky header and top:0 on the rest of the page </p>
</html>

Javascript/jQuery 解决方案

这被标记为 CSS 和 HTML,但我在这里只提到这一点,因为 JS 是在最广泛的浏览器支持下做到这一点的唯一可靠方法。

Salman A 对该问题的回答创建了表格的克隆,并显示了<thead>第一个和<tbody>第二个。这在您的示例中很容易实现 - 见下文:

$(function() {
  $(".fixed_headers").each(function() {
    $(this).wrap("<div class='scrollable-table'></div>");
    $(this).clone().insertBefore(this);
  });
});
.scrollable-table {
  overflow: auto;
  max-height: 200px;
}

.scrollable-table table:nth-child(1) {
  position: sticky;
  left: 0;
  top: 0;
  background-color: #fff;
  margin-bottom: 0;
}

.scrollable-table table:nth-child(1) tbody {
  visibility: collapse;
}

.scrollable-table table:nth-child(2) thead {
  visibility: collapse;
}

th, td {
  width: 100px;
  min-width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
  <div style="max-width: 500px;">
    <table class="fixed_headers">
      <thead>
        <tr>
          <th>Column 1</th>
          <th>Column 2</th>
          <th>Column 3</th>
          <th>Column 4</th>
          <th>Column 5</th>
          <th>Column 6</th>
          <th>Column 7</th>
          <th>Column 8</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
        <tr>
          <td>Data1</td><td>Data2</td><td>Data3</td><td>Data4</td>
          <td>Data5</td><td>Data6</td><td>Data7</td><td>Data8</td>
        </tr>
      </tbody>
    </table>
  </div>
</html>


推荐阅读