问题
I have an HTML table like this one:
table { border-collapse: collapse; }
table thead th:nth-child(1) { width: 180px }
table thead th:nth-child(2) { width: 150px }
table thead th:nth-child(3) { width: 170px }
table thead tr { border-bottom:2px solid #222; }
table tbody tr { border-top:1px solid #ddd; }
table tbody tr:hover { background: #def; }
table tbody td { height: 40px; }
<div>
<table>
<thead>
<tr>
<th>Heading 1</th>
<th>Heading 2</th>
<th>Heading 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Content 1 1</td>
<td>Content 1 2</td>
<td>Content 1 3</td>
</tr>
<tr>
<td>Content 2 1</td>
<td>Content 2 2<br>Line 2<br>Line 3<br>Line 4</td>
<td>Content 2 3</td>
</tr>
<tr>
<td>Content 3 1</td>
<td>Content 3 2</td>
<td>Content 3 3</td>
</tr>
</tbody>
</table>
</div>
The columns are going to have different fixed width values, specified in the CSS, which will define the size of the table. In the example above, the columns are 180px, 150px, and 170px respectively, so the table will be 500px wide.
Because of the design, we need to make the table occupy 100% of the container without resizing the columns. That means that, if for example the screen is 900px, the columns will still occupy their 500px, but the table should stretch until the end of the container to occupy the remaining 400px.
Setting the table width to 100%, and adding a new column that occupies the remaining space automatically would fix the issue. But we have been asked to avoid adding such a column as screen readers will traverse it and read it as an empty cell, which could be confusing for users.
One hacky option would be to add a pseudo-element that occupies the whole width of the page (with the wrapping div
having an overflow: hidden
, like the demo below). But the issue with this solution is that if the table has columns that occupy more than the width of the page, we want the containing div
to scroll, but then we'll see what seems like a huge empty row.
table { border-collapse: collapse; }
table thead th:nth-child(1),
table thead th:nth-child(1) { min-width: 180px }
table thead th:nth-child(2) { min-width: 150px }
table thead th:nth-child(3) { min-width: 170px }
table thead tr { border-bottom:2px solid #222; }
table tbody tr:not(:first-child) { border-top:1px solid #ddd; }
table tbody tr:hover { background: #def; }
table tbody td { height: 40px; }
div {
overflow: hidden;
}
table tr::after {
content: "";
display: block;
width: 100vw;
}
<div>
<table>
<thead>
<tr>
<th>Heading 1</th>
<th>Heading 2</th>
<th>Heading 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Content 1 1</td>
<td>Content 1 2</td>
<td>Content 1 3</td>
</tr>
<tr>
<td>Content 2 1</td>
<td>Content 2 2<br>Line 2<br>Line 3<br>Line 4</td>
<td>Content 2 3</td>
</tr>
<tr>
<td>Content 3 1</td>
<td>Content 3 2</td>
<td>Content 3 3</td>
</tr>
</tbody>
</table>
</div>
Is there an accessible way of having the table occupy the whole width, but the columns only their allotted width?
回答1:
I suggest to change the width of the third column to width: auto
, to left-align the table headers (th
) contents and set the table's width
to 100%. This will stretch the third colum to the right border of the page.
To force the contents of the third column to not be wider than 170px, you can add padding-right: calc(100% - 500px);
to a rule for the third column:
table {
border-collapse: collapse;
width: 100%;
}
table thead th:nth-child(1) {
width: 180px
}
table thead th:nth-child(2) {
width: 150px
}
table thead th:nth-child(3),
table tbody td:nth-child(3){
width: auto;
padding-right: calc(100% - 500px);
}
table thead tr {
border-bottom: 2px solid #222;
}
table tbody tr {
border-top: 1px solid #ddd;
}
table tbody tr:hover {
background: #def;
}
table tbody td {
height: 40px;
}
th {
text-align: left;
}
<div>
<table>
<thead>
<tr>
<th>Heading 1</th>
<th>Heading 2</th>
<th>Heading 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Content 1 1</td>
<td>Content 1 2</td>
<td>Content 1 3</td>
</tr>
<tr>
<td>Content 2 1</td>
<td>Content 2 2<br>Line 2<br>Line 3<br>Line 4</td>
<td>Content 2 3</td>
</tr>
<tr>
<td>Content 3 1</td>
<td>Content 3 2</td>
<td>Content 3 3 lots of content lots of content lots of content </td>
</tr>
</tbody>
</table>
</div>
回答2:
I would consider making the last column to always fill the remaining space and use padding inside to force the content to have a fixed width since it cannot overflow the padding.
Simply pay attention to the calculation if you want an accurate result:
table {
border-collapse: collapse;
}
table thead th:nth-child(1),
table thead th:nth-child(1) {
min-width: 180px
}
table thead th:nth-child(2) {
min-width: 150px
}
table thead th:nth-child(3),
table tr td:nth-child(3){
width: 100%;
min-width:170px;
/*2x2px + 1px is for the default border-spacing*/
padding-right:calc(100% - 150px - 180px - 170px - (2*2px + 1px));
}
table thead tr {
border-bottom: 2px solid #222;
}
table tbody tr:not(:first-child) {
border-top: 1px solid #ddd;
}
table tbody tr:hover {
background: #def;
}
table tbody td {
height: 40px;
}
div {
overflow: hidden;
}
<div>
<table>
<thead>
<tr>
<th>Heading 1</th>
<th>Heading 2</th>
<th>Heading 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Content 1 1</td>
<td>Content 1 2</td>
<td>Content 1 3</td>
</tr>
<tr>
<td>Content 2 1</td>
<td>Content 2 2<br>Line 2<br>Line 3<br>Line 4</td>
<td>Content 2 3</td>
</tr>
<tr>
<td>Content 3 1 with very long word here</td>
<td>Content 3 2</td>
<td>Content 3 3 with very long word here</td>
</tr>
</tbody>
</table>
</div>
Same idea with different values:
table {
border-collapse: collapse;
}
table thead th:nth-child(1),
table thead th:nth-child(1) {
width: 180px
}
table thead th:nth-child(2) {
width: 150px
}
table thead th:nth-child(3),
table tr td:nth-child(3){
width: calc(100% - 150px - 180px - 2*2px);
min-width:170px;
/*3x2px + 1px is for the default border-spacing*/
padding-right:calc(100% - 150px - 180px - 170px - (2*2px + 1px));
}
table thead tr {
border-bottom: 2px solid #222;
}
table tbody tr:not(:first-child) {
border-top: 1px solid #ddd;
}
table tbody tr:hover {
background: #def;
}
table tbody td {
height: 40px;
}
div {
overflow: hidden;
}
<div>
<table>
<thead>
<tr>
<th>Heading 1</th>
<th>Heading 2</th>
<th>Heading 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Content 1 1</td>
<td>Content 1 2</td>
<td>Content 1 3</td>
</tr>
<tr>
<td>Content 2 1</td>
<td>Content 2 2<br>Line 2<br>Line 3<br>Line 4</td>
<td>Content 2 3</td>
</tr>
<tr>
<td>Content 3 1 with very long word here</td>
<td>Content 3 2</td>
<td>Content 3 3 with very long word here</td>
</tr>
</tbody>
</table>
</div>
回答3:
A solution that we opted for was probably the most simple thing to do: adding the extra empty column -which as it doesn't have any specific width, it will stretch and expand to fill the remaining space-... and adding aria-ignore="true"
to the cells in that column.
Still a bit hacky, but after testing in Chrome (with VoiceOver and ChromeVox), Firefox (with NVDA), and Internet Explorer 11 (with NVDA and JAWS), all the screen readers ignore that cell (users cannot navigate to it with the keyboard) to the point that they are not even counted for column count (the readers will read "Entering/Exiting a table with four rows and 3 columns").
Here is the code:
table { border-collapse: collapse; }
table thead th:nth-child(1) { width: 180px }
table thead th:nth-child(2) { width: 150px }
table thead th:nth-child(3) { width: 170px }
table thead tr { border-bottom:2px solid #222; }
table tbody tr { border-top:1px solid #ddd; }
table tbody tr:hover { background: #def; }
table tbody td { height: 40px; }
table {
width: 100%;
table-layout: fixed;
}
<div>
<table>
<thead>
<tr>
<th>Heading 1</th>
<th>Heading 2</th>
<th>Heading 3</th>
<th aria-hidden="true"></th>
</tr>
</thead>
<tbody>
<tr>
<td>Content 1 1</td>
<td>Content 1 2</td>
<td>Content 1 3</td>
<td aria-hidden="true"></td>
</tr>
<tr>
<td>Content 2 1</td>
<td>Content 2 2<br>Line 2<br>Line 3<br>Line 4</td>
<td>Content 2 3</td>
<td aria-hidden="true"></td>
</tr>
<tr>
<td>Content 3 1</td>
<td>Content 3 2</td>
<td>Content 3 3</td>
<td aria-hidden="true"></td>
</tr>
</tbody>
</table>
</div>
来源:https://stackoverflow.com/questions/56878231/table-that-occupies-full-width-even-when-the-columns-dont