恐怕没有完美的解决方案。
我会给你不同的选择,你需要决定放弃什么。
绝对定位的列。
✅ 纯 CSS - ✅ 旧浏览器 - ❌ 灵活的宽度 - ❌ 适当的突出显示
关键是为前三列设置一个固定的width,然后将.wrapped元素的margin-left属性设置为等于列的总宽度。
.wrapper {
overflow-x: scroll;
overflow-y: visible;
margin-left: 18em;
width: 15em;
background-color: greenyellow;
}
td,
th {
vertical-align: top;
border-top: 1px solid #ccc;
padding: 0.8em;
}
th, tr:nth-of-type(1) td {
height: 1em;
}
th:nth-of-type(1),
td:nth-of-type(1) {
position: absolute;
left: 0em;
width: 6em;
}
th:nth-of-type(2),
td:nth-of-type(2) {
position: absolute;
left: 6em;
width: 6em;
}
th:nth-of-type(3),
td:nth-of-type(3) {
position: absolute;
left: 12em;
width: 6em;
}
tr:hover td {
background-color: yellow;
}
<div class="wrapper">
<table>
<thead>
<tr>
<th>Header-1</th>
<th>Header-2</th>
<th>Header-3</th>
<th>Header-4</th>
<th>Header-5</th>
<th>Header-5</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>col 1 - A</td>
<td>col 2 - A</td>
<td>col 3 - A</td>
<td>col 4 - A (WITH LONGER CONTENT)</td>
<td>col 5 - A</td>
<td>col 6 - A</td>
</tr>
<tr>
<td>col 1 - B</td>
<td>col 2 - B</td>
<td>col 3 - B</td>
<td>col 4 - B</td>
<td>col 5 - B</td>
<td>col 6 - B</td>
</tr>
<tr>
<td>col 1 - C</td>
<td>col 2 - C</td>
<td>col 3 - C</td>
<td>col 4 - C</td>
<td>col 5 - C</td>
<td>col 6 - C (WITH_A_LONG_WORD)</td>
</tr>
</tbody>
</table>
绝对定位的列 + JavaScript。
❌ 纯 CSS - ✅ 旧浏览器 - ✅ 灵活宽度 - ❌ 适当突出显示
这里,我们没有预先硬编码列的width,而是使用JS计算和设置width。
更好的 JS 实现是可能的。举个例子吧。
let wrapper = document.querySelector('.wrapper');
let cols = document.querySelectorAll('th');
let widthCol0 = cols[0].offsetWidth;
let widthCol1 = cols[1].offsetWidth;
let widthCol2 = cols[2].offsetWidth;
stylesheet = document.styleSheets[0]
stylesheet.insertRule('th:nth-of-type(1), td:nth-of-type(1) { left: 0px; position: absolute; width: ' + widthCol0 + 'px;}', 0);
stylesheet.insertRule('th:nth-of-type(2), td:nth-of-type(2) { left: ' + widthCol0 + 'px; position: absolute; width: ' + widthCol1 + 'px;}', 0);
stylesheet.insertRule('th:nth-of-type(3), td:nth-of-type(3) { left: ' + (widthCol0 + widthCol1) + 'px; position: absolute; width: ' + widthCol2 + 'px;}', 0);
wrapper.style.marginLeft = (widthCol0 + widthCol1 + widthCol2) + 'px';
.wrapper {
overflow-x: scroll;
overflow-y: visible;
width: 15em;
background-color: greenyellow;
}
td,
th {
vertical-align: top;
border-top: 1px solid #ccc;
padding: 0.8em;
}
th, tr:nth-of-type(1) td {
height: 1em;
}
tr:hover td {
background-color: yellow;
}
<div class="wrapper">
<table>
<thead>
<tr>
<th>Header-1</th>
<th>Header-2</th>
<th>Header-3</th>
<th>Header-4</th>
<th>Header-5</th>
<th>Header-5</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>col 1 - A (WITH LONGER CONTENT)</td>
<td>col 2 - A</td>
<td>col 3 - A</td>
<td>col 4 - A (WITH LONGER CONTENT)</td>
<td>col 5 - A</td>
<td>col 6 - A</td>
</tr>
<tr>
<td>col 1 - B</td>
<td>col 2 - B</td>
<td>col 3 - B</td>
<td>col 4 - B</td>
<td>col 5 - B</td>
<td>col 6 - B</td>
</tr>
<tr>
<td>col 1 - C</td>
<td>col 2 - C (WITH_A_LONG_WORD)</td>
<td>col 3 - C</td>
<td>col 4 - C</td>
<td>col 5 - C</td>
<td>col 6 - C (WITH_A_LONG_WORD)</td>
</tr>
</tbody>
</table>
固定位置的列。
✅ 纯 CSS - ❌ 旧浏览器 - ❌ 灵活的宽度 - ✅ 适当的突出显示
我真的很喜欢@Dominic 展示的position: sticky 解决方案。如果你don't need to support IE,这是要走的路。
放弃 IE 支持是有回报的。您可以有适当的突出显示,前三列的宽度将适应内容。
尽管如此,即使您不需要硬编码 width,您也需要硬编码 left 属性以设置列在哪个点变为粘性。这种做法违背了灵活的width 的意义。没有办法。
.wrapper {
width: 40em;
overflow-x: scroll;
}
td,
th {
vertical-align: top;
border-top: 1px solid #ccc;
padding: 0.8em;
}
th,
tr:nth-of-type(1) td {
height: 1em;
}
th:nth-of-type(1), td:nth-of-type(1),
th:nth-of-type(2), td:nth-of-type(2),
th:nth-of-type(3), td:nth-of-type(3) {
background-color: white;
position: sticky;
}
th:nth-of-type(1), td:nth-of-type(1) {
left: 0em;
}
th:nth-of-type(2), td:nth-of-type(2) {
left: 6em;
}
th:nth-of-type(3), td:nth-of-type(3) {
left: 12em;
}
tr:hover td{
background-color: yellow;
}
<div class="wrapper">
<table>
<thead>
<tr>
<th>Header-1</th>
<th>Header-2</th>
<th>Header-3</th>
<th>Header-4</th>
<th>Header-5</th>
<th>Header-6</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>col 1 - A (WITH LONGER CONTENT)</td>
<td>col 2 - A</td>
<td>col 3 - A</td>
<td>col 4 - A (WITH LONGER CONTENT)</td>
<td>col 5 - A</td>
<td>col 6 - A</td>
</tr>
<tr>
<td>col 1 - B</td>
<td>col 2 - B</td>
<td>col 3 - B</td>
<td>col 4 - B</td>
<td>col 5 - B</td>
<td>col 6 - B</td>
</tr>
<tr>
<td>col 1 - C</td>
<td>col 2 - C (WITH_A_LONG_WORD)</td>
<td>col 3 - C</td>
<td>col 4 - C</td>
<td>col 5 - C</td>
<td>col 6 - C (WITH_A_LONG_WORD)</td>
</tr>
</tbody>
</table>
</div>
固定定位列 + JavaScript。
❌ 纯 CSS - ❌ 旧浏览器 - ✅ 灵活的宽度 - ✅ 适当的突出显示
此示例的 HTML 和 CSS 与上面的示例完全相同。
和我们的第二个例子一样,我们使用 JS 来计算列的width。在这种情况下,我们使用它来覆盖 left 属性。另外,JS代码更直接。
如果我们稍后要用 JS 设置 left 属性,为什么还要在 CSS 中设置它?因为如果客户端不运行 JS,我们不希望列完全折叠,破坏我们的布局。
let cols = document.querySelectorAll('th');
let widthCol0 = cols[0].offsetWidth;
let widthCol1 = cols[1].offsetWidth;
stylesheet = document.styleSheets[0];
stylesheet.insertRule('th:nth-of-type(2), td:nth-of-type(2) { left: ' + widthCol0 + 'px !important;}', 0);
stylesheet.insertRule('th:nth-of-type(3), td:nth-of-type(3) { left: ' + (widthCol0 + widthCol1) + 'px !important;', 0);
.wrapper {
width: 40em;
overflow-x: scroll;
}
td,
th {
vertical-align: top;
border-top: 1px solid #ccc;
padding: 0.8em;
}
th,
tr:nth-of-type(1) td {
height: 1em;
}
th:nth-of-type(1), td:nth-of-type(1),
th:nth-of-type(2), td:nth-of-type(2),
th:nth-of-type(3), td:nth-of-type(3) {
background-color: white;
position: sticky;
}
th:nth-of-type(1), td:nth-of-type(1) {
left: 0em;
}
th:nth-of-type(2), td:nth-of-type(2) {
left: 6em;
}
th:nth-of-type(3), td:nth-of-type(3) {
left: 12em;
}
tr:hover td{
background-color: yellow;
}
<div class="wrapper">
<table>
<thead>
<tr>
<th>Header-1</th>
<th>Header-2</th>
<th>Header-3</th>
<th>Header-4</th>
<th>Header-5</th>
<th>Header-6</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>col 1 - A (WITH LONGER CONTENT)</td>
<td>col 2 - A</td>
<td>col 3 - A</td>
<td>col 4 - A (WITH LONGER CONTENT)</td>
<td>col 5 - A</td>
<td>col 6 - A</td>
</tr>
<tr>
<td>col 1 - B</td>
<td>col 2 - B</td>
<td>col 3 - B</td>
<td>col 4 - B</td>
<td>col 5 - B</td>
<td>col 6 - B</td>
</tr>
<tr>
<td>col 1 - C</td>
<td>col 2 - C (WITH_A_LONG_WORD)</td>
<td>col 3 - C</td>
<td>col 4 - C</td>
<td>col 5 - C</td>
<td>col 6 - C (WITH_A_LONG_WORD)</td>
</tr>
</tbody>
</table>
</div>
最后的笔记
由您决定哪种方法最适合您的需求。
就我个人而言,我认为第四个最强大,因为:
我认为这没什么大不了的。当然,如果您正在为使用 IE11 为首选浏览器的 Intranet 进行编程,请采用第一种或第二种方法。