这个想法是表头将粘在整个表上,而帐户标题将粘在表头的正下方,但仅限于它们自己的部分。
这是否可以通过不破坏屏幕阅读器体验的方式实现?理想情况下,有一种方法可以使用语义 HTML 来做到这一点,不需要任何 hack,但我对所有解决方案持开放态度。 这里的主要目标是让键盘用户和屏幕阅读器都能获得这种体验。
标题将允许用户对整个表格进行排序。例如,按成本升序排序会将每个账户下的交易顺序更改为交易 3、2、1 和交易 6、5、4,但账户部分将保持在相同位置。 我不确定这是否会改变事情。
这是一个格式正确的示例
<table>
,来自 HTML 规范:
<table>
<thead>
<tr> <th> ID <th> Measurement <th> Average <th> Maximum
<tbody>
<tr> <td> <th scope=rowgroup> Cats <td> <td>
<tr> <td> 93 <th> Legs <td> 3.5 <td> 4
<tr> <td> 10 <th> Tails <td> 1 <td> 1
<tbody>
<tr> <td> <th scope=rowgroup> English speakers <td> <td>
<tr> <td> 32 <th> Legs <td> 2.67 <td> 4
<tr> <td> 35 <th> Tails <td> 0.33 <td> 1
</table>
如您所见,一个表可以有多个
<tbody>
元素对应于多个行组。带有 scope="rowgroup"
的标题为剩余行组提供标签。
对于格式良好且易于访问的表格,我们可以像往常一样提供列标题和行标题。更重要的是,我们可以将每个“Account”部分标记为
<tbody>
,并为每个部分提供行组标题:
table {
border-collapse: collapse;
}
th, td {
padding: .5rem 1.25rem;
border: 1px solid black;
}
thead th {
background-color: #d3deea;
}
tbody th {
text-align: start;
}
tbody > tr:first-child > th {
background-color: #a7e3e4;
}
<table>
<thead>
<tr>
<th>Name</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 123</th>
</tr>
<tr>
<td>Trx 1</td>
<td>20</td>
</tr>
<tr>
<td>Trx 2</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 456</th>
</tr>
<tr>
<td>Trx 2</td>
<td>30</td>
</tr>
<tr>
<td>Trx 3</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
</table>
但是,我们不能天真地使单元格粘住,因为边界将保持在原位:
/* Sticky */
thead > tr > th {
position: sticky;
top: 0;
}
tbody > tr:first-child > th {
position: sticky;
top: calc(1rem + 1lh + 1px); /* Offset by height of `thead > tr` */
}
/* Styling */
table {
border-collapse: collapse;
}
th, td {
padding: .5rem 1.25rem;
border: 1px solid black;
}
thead th {
background-color: #d3deea;
}
tbody th {
text-align: start;
}
tbody > tr:first-child > th {
background-color: #a7e3e4;
}
<table>
<thead>
<tr>
<th>Name</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 123</th>
</tr>
<tr>
<td>Trx 1</td>
<td>20</td>
</tr>
<tr>
<td>Trx 2</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 456</th>
</tr>
<tr>
<td>Trx 2</td>
<td>30</td>
</tr>
<tr>
<td>Trx 3</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 123</th>
</tr>
<tr>
<td>Trx 1</td>
<td>20</td>
</tr>
<tr>
<td>Trx 2</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 456</th>
</tr>
<tr>
<td>Trx 2</td>
<td>30</td>
</tr>
<tr>
<td>Trx 3</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 123</th>
</tr>
<tr>
<td>Trx 1</td>
<td>20</td>
</tr>
<tr>
<td>Trx 2</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 456</th>
</tr>
<tr>
<td>Trx 2</td>
<td>30</td>
</tr>
<tr>
<td>Trx 3</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 123</th>
</tr>
<tr>
<td>Trx 1</td>
<td>20</td>
</tr>
<tr>
<td>Trx 2</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 456</th>
</tr>
<tr>
<td>Trx 2</td>
<td>30</td>
</tr>
<tr>
<td>Trx 3</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 123</th>
</tr>
<tr>
<td>Trx 1</td>
<td>20</td>
</tr>
<tr>
<td>Trx 2</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 456</th>
</tr>
<tr>
<td>Trx 2</td>
<td>30</td>
</tr>
<tr>
<td>Trx 3</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 123</th>
</tr>
<tr>
<td>Trx 1</td>
<td>20</td>
</tr>
<tr>
<td>Trx 2</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 456</th>
</tr>
<tr>
<td>Trx 2</td>
<td>30</td>
</tr>
<tr>
<td>Trx 3</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
</table>
要“解决”边界问题,绝对将“边界”放置在顶部。一个简单的解决方案是使用 ::after
伪元素作为边框:
/* Sticky */
thead > tr > th {
position: sticky;
top: 0;
}
tbody > tr:first-child > th {
position: sticky;
top: calc(1rem + 1lh + 1px); /* Offset by height of `thead > tr` */
}
/* Border of sticky headers */
thead > tr > th::after,
tbody > tr:first-child > th::after {
content: "";
position: absolute;
top: -1px;
left: -1px;
width: 100%;
height: 100%;
border: 1px solid black;
display: block;
pointer-events: none;
}
/* Styling */
table {
border-collapse: collapse;
}
th, td {
padding: .5rem 1.25rem;
border: 1px solid black;
}
thead th {
background-color: #d3deea;
}
tbody th {
text-align: start;
}
tbody > tr:first-child > th {
background-color: #a7e3e4;
}
<table>
<thead>
<tr>
<th>Name</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 12</th>
</tr>
<tr>
<td>Trx 1</td>
<td>20</td>
</tr>
<tr>
<td>Trx 2</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 34</th>
</tr>
<tr>
<td>Trx 3</td>
<td>30</td>
</tr>
<tr>
<td>Trx 4</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 56</th>
</tr>
<tr>
<td>Trx 5</td>
<td>20</td>
</tr>
<tr>
<td>Trx 6</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 78</th>
</tr>
<tr>
<td>Trx 7</td>
<td>30</td>
</tr>
<tr>
<td>Trx 8</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 910</th>
</tr>
<tr>
<td>Trx 9</td>
<td>20</td>
</tr>
<tr>
<td>Trx 10</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 1112</th>
</tr>
<tr>
<td>Trx 11</td>
<td>30</td>
</tr>
<tr>
<td>Trx 12</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 1314</th>
</tr>
<tr>
<td>Trx 13</td>
<td>20</td>
</tr>
<tr>
<td>Trx 14</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 1516</th>
</tr>
<tr>
<td>Trx 15</td>
<td>30</td>
</tr>
<tr>
<td>Trx 16</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 1718</th>
</tr>
<tr>
<td>Trx 17</td>
<td>20</td>
</tr>
<tr>
<td>Trx 18</td>
<td>15</td>
</tr>
<tr>
<th>Total</th>
<td>35</td>
</tr>
</tbody>
<tbody>
<tr>
<th colspan="2" scope="rowgroup">Account 1920</th>
</tr>
<tr>
<td>Trx 19</td>
<td>30</td>
</tr>
<tr>
<td>Trx 20</td>
<td>20</td>
</tr>
<tr>
<th>Total</th>
<td>50</td>
</tr>
</tbody>
</table>
注意:如果没有 pointer-events: none
::after
伪元素(“扩展”其父单元格的区域)将捕获指针事件,从而防止事件到达单元格的子级(例如按钮)。