【问题标题】:CSS to create frozen row and column headers in table within overflow div?CSS在溢出div中的表中创建冻结的行和列标题?
【发布时间】:2015-09-17 05:28:31
【问题描述】:

我正在尝试在内容包装器内的表格中实现冻结的行和列标题(类似于 Excel)。由于屏幕上需要存在其他移动元素,利用 position:absolute 属性的 CSS 技巧对我来说似乎并不可靠。

这个想法是,当页面加载时,表格如下所示。 灰色 区域代表我无法删除的周围内容。 redgreenpurple 框代表我要冻结的行和列标题,以便它们在用户访问时保持原位滚动或平移 白色 区域。

如图所示,内容很可能会垂直延伸到浏览器中最初显示的内容之外,因此当用户向下滚动时,列标题会达到理想状态,如下图所示。 但是,这是一个不错的选择,不是必需的。即使标题会留在页面上首次加载的位置,我也将不胜感激。

此外,与 Excel 一样,水平滚动应该不影响行标题,同时使列标题随内容移动。

有没有办法可靠地实现这个功能?我创建了一个 JSFiddle 来说明我正在使用的场景和内容包装器:http://jsfiddle.net/Jr5Zt/3/

<table id="bodyTable">
    <tbody><tr><td id="bodyCell">
        <!-- my custom content -->
    </td></tr></tbody>
</table>

【问题讨论】:

  • 我以前用纯 CSS 做过固定的列标题,这真的很痛苦。概括地说,将&lt;th&gt; 内容包装在&lt;span&gt; 标记中,绝对定位那些&lt;span&gt; 标记,并为&lt;tbody&gt; 添加足够的顶部填充以为标题腾出空间。这听起来可能还不错,但是当您开始处理标题样式时,它很快就会失控。同时对行“标题”做类似的事情的想法让我做噩梦。如果我是你,我只会在它真的很重要并且你有很多时间来调试它时才追求它。
  • 还有一些使用JavaScript的方法(例如克隆表格,隐藏克隆体和原始标题行等)但是这些方法都有自己的问题。
  • 感谢马塞洛的建议。我认为使用 div 的想法是实现浮动或“冻结”标题的正确方法。使用表格的局限性太大,尽管它确实很方便。

标签: html css


【解决方案1】:

我还没有找到执行以下操作的纯 html/css 解决方案:

  • 在语义上使用表格
  • 修复了标题和列
  • 适用于可变宽度列
  • 适用于垂直和水平滚动

这是我一起破解的东西,确实有效

http://codepen.io/saiidi/pen/mePdqo

我不喜欢它的是 header th 元素中的内容是重复的。我认为通过一些额外的黑客攻击可以解决这个问题。

本着将代码放入答案的精神,代码如下:

html:

<div class="scrolly">
  <div class="scrollx">
    <table>
      <thead>
        <tr>
          <th class="sticky"><div>1</div></th>
          <th class="sticky"><div>2</div></th>
          <th>header 1<div>header 1</div></th>
          <th>header 2<div>header 2</div></th>
          <th>header 3<div>header 3</div></th>
          <th>header 4<div>header 4</div></th>
          <th>header 5<div>header 5</div></th>
          <th>header 6<div>header 6</div></th>
          <th>header 7<div>header 7</div></th>
          <th>header 8<div>header 8</div></th>
          <th>header 9<div>header 9</div></th>
          <th>header 10<div>header 10</div></th>
          <th>header 11<div>header 11</div></th>
          <th>header 12<div>header 12</div></th>
          <th>header 13<div>header 13</div></th>
          <th>header 14<div>header 14</div></th>
          <th>header 15<div>header 15</div></th>
          <th>header 16<div>header 16</div></th>
          <th>header 17<div>header 17</div></th>
          <th>header 18<div>header 18</div></th>
          <th>header 19<div>header 19</div></th>
          <th>header 20<div>header 20</div></th>
          <th class="fill"></th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td class="sticky">hello 1</td>
          <td class="sticky">hello</td>
          <td>world 1</td>
          <td>world 2</td>
          <td>world 3</td>
          <td>world 4</td>
          <td>world 5</td>
          <td>world 6</td>
          <td>world 7</td>
          <td>world 8</td>
          <td>world 9</td>
          <td>world 10</td>
          <td>world 11</td>
          <td>world 12</td>
          <td>world 13</td>
          <td>world 14</td>
          <td>world 15</td>
          <td>world 16</td>
          <td>world 17</td>
          <td>world 18</td>
          <td>world 19</td>
          <td>world 20</td>
          <td class="fill"></td>
        </tr>
        <tr>
          <td class="sticky">hello 2</td>
          <td class="sticky">hello</td>
          <td>world 1</td>
          <td>world 2</td>
          <td>world 3</td>
          <td>world 4</td>
          <td>world 5</td>
          <td>world 6</td>
          <td>world 7</td>
          <td>world 8</td>
          <td>world 9</td>
          <td>world 10</td>
          <td>world 11</td>
          <td>world 12</td>
          <td>world 13</td>
          <td>world 14</td>
          <td>world 15</td>
          <td>world 16</td>
          <td>world 17</td>
          <td>world 18</td>
          <td>world 19</td>
          <td>world 20</td>
          <td class="fill"></td>
        </tr>
        <tr>
          <td class="sticky">hello 3</td>
          <td class="sticky">hello</td>
          <td>world 1</td>
          <td>world 2</td>
          <td>world 3</td>
          <td>world 4</td>
          <td>world 5</td>
          <td>world 6</td>
          <td>world 7</td>
          <td>world 8</td>
          <td>world 9</td>
          <td>world 10</td>
          <td>world 11</td>
          <td>world 12</td>
          <td>world 13</td>
          <td>world 14</td>
          <td>world 15</td>
          <td>world 16</td>
          <td>world 17</td>
          <td>world 18</td>
          <td>world 19</td>
          <td>world 20</td>
          <td class="fill"></td>
        </tr>
        <tr>
          <td class="sticky">hello 4</td>
          <td class="sticky">hello</td>
          <td>world 1</td>
          <td>world 2</td>
          <td>world 3</td>
          <td>world 4</td>
          <td>world 5</td>
          <td>world 6</td>
          <td>world 7</td>
          <td>world 8</td>
          <td>world 9</td>
          <td>world 10</td>
          <td>world 11</td>
          <td>world 12</td>
          <td>world 13</td>
          <td>world 14</td>
          <td>world 15</td>
          <td>world 16</td>
          <td>world 17</td>
          <td>world 18</td>
          <td>world 19</td>
          <td>world 20</td>
          <td class="fill"></td>
        </tr>
        <tr>
          <td class="sticky">hello 5</td>
          <td class="sticky">hello</td>
          <td>world 1</td>
          <td>world 2</td>
          <td>world 3</td>
          <td>world 4</td>
          <td>world 5</td>
          <td>world 6</td>
          <td>world 7</td>
          <td>world 8</td>
          <td>world 9</td>
          <td>world 10</td>
          <td>world 11</td>
          <td>world 12</td>
          <td>world 13</td>
          <td>world 14</td>
          <td>world 15</td>
          <td>world 16</td>
          <td>world 17</td>
          <td>world 18</td>
          <td>world 19</td>
          <td>world 20</td>
          <td class="fill"></td>
        </tr>
        <tr>
          <td class="sticky">hello 6</td>
          <td class="sticky">hello</td>
          <td>world 1</td>
          <td>world 2</td>
          <td>world 3</td>
          <td>world 4</td>
          <td>world 5</td>
          <td>world 6</td>
          <td>world 7</td>
          <td>world 8</td>
          <td>world 9</td>
          <td>world 10</td>
          <td>world 11</td>
          <td>world 12</td>
          <td>world 13</td>
          <td>world 14</td>
          <td>world 15</td>
          <td>world 16</td>
          <td>world 17</td>
          <td>world 18</td>
          <td>world 19</td>
          <td>world 20</td>
          <td class="fill"></td>
        </tr>
        <tr>
          <td class="sticky">hello 7</td>
          <td class="sticky">hello</td>
          <td>world 1</td>
          <td>world 2</td>
          <td>world 3</td>
          <td>world 4</td>
          <td>world 5</td>
          <td>world 6</td>
          <td>world 7</td>
          <td>world 8</td>
          <td>world 9</td>
          <td>world 10</td>
          <td>world 11</td>
          <td>world 12</td>
          <td>world 13</td>
          <td>world 14</td>
          <td>world 15</td>
          <td>world 16</td>
          <td>world 17</td>
          <td>world 18</td>
          <td>world 19</td>
          <td>world 20</td>
          <td class="fill"></td>
        </tr>
        <tr>
          <td class="sticky">hello 8</td>
          <td class="sticky">hello</td>
          <td>world 1</td>
          <td>world 2</td>
          <td>world 3</td>
          <td>world 4</td>
          <td>world 5</td>
          <td>world 6</td>
          <td>world 7</td>
          <td>world 8</td>
          <td>world 9</td>
          <td>world 10</td>
          <td>world 11</td>
          <td>world 12</td>
          <td>world 13</td>
          <td>world 14</td>
          <td>world 15</td>
          <td>world 16</td>
          <td>world 17</td>
          <td>world 18</td>
          <td>world 19</td>
          <td>world 20</td>
          <td class="fill"></td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

css:

td, th {
  padding: 5px;
  white-space: nowrap;
}

td {
  background: linear-gradient(135deg, white 0%, #a80077 99%, black 100%);
}

th {
  height: 0;
  font-weight: normal;
}

.scrollx {
  max-width: 100%;
  overflow-x: scroll;
}

.scrolly {
  position: relative;
  max-height: 150px;
  overflow-y: scroll;
  margin-bottom: 20px;
}

table {
  border-collapse: collapse;
  min-width: 100%;
}

table td.fill,
table th.fill {
  width: 100%;
  min-width: 0;
  background: white;
  padding: 0;
}

tr {
  position: relative;
}

.sticky {
  text-decoration: underline;
  font-weight: 700;
}

.stuck {
  position: absolute;
}

thead th {
  position: relative;
}
thead th div {
  padding: 5px;
  background: linear-gradient(135deg, black 0%, #a80077 99%, white 100%);
  color: #ffffff;
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  right: 0;
}

js:

$(function() {
  $("#status").text('loaded');


  $("table").each(function(index, table) {
    var firstRow = $($(table).find('tr')[0]);
    var offset = 0;
    var stickies = firstRow.find('.sticky');

    firstRow.children().each(function(index, td) {
      var width = $(td).width();
      $(table).find('tr td:nth-of-type('+(index+1)+')').css({width: width + 'px'});
      $(table).find('tr th:nth-of-type('+(index+1)+')').css({width: width + 'px'});
    });

    stickies.each(function(index, td) {
      var column = $(table).find('tr .sticky:nth-of-type('+(index+1)+')');
      column.css({left: offset+'px'});
      column.addClass('stuck');
      offset += $(td).width() + 10;
    });

    $(table).parent().css({"margin-left": offset+'px'});

    $(table).parent().parent().scroll(function(e) {
      var top = e.currentTarget.scrollTop;
      $(table).find('thead tr th div').css({top:top+'px'});
    });
  });
});

那么,这是在做什么呢?

它在固定(或“粘性”)列上使用绝对定位来保持卡在左侧。为了支持可变宽度,它在将位置设置为绝对之前计算宽度。然后在表格容器的左侧应用边距以补偿绝对定位的列。

为了修复标题,它绝对将嵌套的 div 定位在第 th 元素上,然后在表格滚动时调整它们的“top”css 属性。为什么重复的内容?它的存在是为了让列宽正确地考虑到标题内容的宽度。

这是一个相当粗略的实现——这里的 jquery 代码是为了证明概念。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 2016-04-01
    • 2010-09-20
    • 1970-01-01
    相关资源
    最近更新 更多