html - CSS 在溢出 div 的表中创建卡住的行和列标题?

标签 html css

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

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

Frozen headers starting position

如图所示,内容很可能会垂直延伸到浏览器中最初显示的内容之外,因此理想情况下,当用户向下滚动时,列标题会凸起到顶部,如下图所示。 但是,这是可有可无的,不是必需的。即使标题只保留在页面上首次加载的位置,我也将不胜感激。

Frozen headers after vertical scrolling

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

Frozen headers after horizontal scrolling

有什么方法可以可靠地实现此功能?我创建了一个 JSFiddle,它说明了我正在工作的场景和内容包装器:http://jsfiddle.net/Jr5Zt/3/

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

最佳答案

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

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

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

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

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

本着将代码放入答案的精神,这里是代码:

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 个元素上,然后在表格滚动时调整它们的“顶部”css 属性。为什么重复的内容?它在那里,以便列宽正确考虑标题内容的宽度。

这是一个非常粗略的实现 - 此处的 jquery 代码旨在证明概念。

关于html - CSS 在溢出 div 的表中创建卡住的行和列标题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21712931/

相关文章:

html - &lt;iframe&gt; 未使用 css 网格(Chrome、Edge、Opera)中的可用空间,但它适用于 Firefox

html - 在 2 个 div 之间的中间 div 中居中内容

html - 如何仅使用 CSS 使页眉和页脚之间的 div 响应高度?

html - IE7 检查停止页面在 IE8 中显示

php - 仅在插件页面 WordPress 上显示样式表

css - 选择除第一个以外的所有 'tr'

html - Servlet返回“HTTP状态404请求的资源(/Servlet)不可用”

html - 在 Twitter Bootstrap 中更改 .btn-navbar 的颜色

html - 如何垂直对齐 float 图像中的替代文本?

css - 单行 div 内不成比例的流体图像缩放