我正在尝试在内容包装器内的表格中实现卡住的行和列标题(类似于 Excel)。由于需要在屏幕上显示其他移动元素,利用 position:absolute 属性的 CSS 技巧对我来说似乎无法可靠地工作。
想法是当页面加载时,表格如下所示。 灰色 区域代表我无法删除的周围内容。 红色、绿色 和紫色 框代表我想要卡住的行和列标题,以便它们在用户使用时保持原位滚动或平移白色区域。
如图所示,内容很可能会垂直延伸到浏览器中最初显示的内容之外,因此理想情况下,当用户向下滚动时,列标题会凸起到顶部,如下图所示。 但是,这是可有可无的,不是必需的。即使标题只保留在页面上首次加载的位置,我也将不胜感激。
此外,与 Excel 一样,水平滚动应该保留行标题,同时使列标题随内容移动。
有什么方法可以可靠地实现此功能?我创建了一个 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/