【问题标题】:Table with fixed position of columns without setting height and width of td and th列位置固定的表格,不设置 td 和 th 的高度和宽度
【发布时间】:2020-02-03 23:28:10
【问题描述】:

我有一个固定前三列的表。我的前三列是固定的。我想要的是其余列应该根据它们的内容自动计算它们的heightwidth

所以我的 CSS 看起来像这样:

.outer {
    position:relative;
    background-color: hotpink;
}
.inner {
    overflow-x:scroll;
    overflow-y: visible;
    width: calc(100% - 1500px);
    margin-left: 18em;
    background-color: greenyellow;
}

table {
    table-layout: fixed;
    width: 100%;
}

td, th {
    vertical-align: top;
    border-top: 1px solid #ccc;
    padding: 0.8em;
    width: 150px;
    height: 42px;
    word-break: break-all;
}

.col1 {
    position:absolute;
    left: 0em;
    width: 6em;
}

.col2 {
    position:absolute;
    left: 6em;
    width: 6em;
 }

.col3 {
    position:absolute;
    left: 12em;
    width: 6em;
}

.emptyrow {
    position:absolute;
    left: 0em;
    width: 18em;
}

这是表格的 HTML:

<div class="outer">
    <div class="inner">
      <table>
        <thead>
          <tr>
            <th class="col1">Header 1</th>
            <th class="col2">Header 2</th>
            <th class="col3">Header 3</th>
            <th>Header 4</th>
            <th>Header 5</th>
            <th>Header 6</th>
            <th>Header 7</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td class="emptyrow">This column should have value.</td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
          </tr>
          <tr>
            <td class="col1">col 1 - B</td>
            <td class="col2">col 2 - B</td>
            <td class="col3">col 3 - B</td>
            <td>col 4 - B</td>
            <td>col 5 - B</td>
            <td>col 6 - B</td>
            <td>col 7 - B</td>

          </tr>
          <tr>
            <td class="col1">col 1 - C</td>
            <td class="col2">col 2 - C</td>
            <td class="col3">col 3 - C</td>
            <td>col 4 - C</td>
            <td>col 5 - C</td>
            <td>col 6 - C</td>
            <td>col 7 - C</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>

是否可以避免在tdth 中设置宽度和高度?

我的意思是避免heightwidth 的硬编码值:

td, th {
  ...
  width:6em;
  height: 4em;
}

是否可以只使用没有 JavaScript 的纯 CSS?如果无法使用此解决方案实施,那么看到另一种方法真的很棒。

要求:

  1. 某些滚动列可以为空
  2. 应该有滚动条从“标题 4”滚动列
  3. 标题 1-3 应始终保持在同一位置
  4. 所有列中的Padding 应为0.8em
  5. WidthHeighttdth 不应被硬编码。它们应该符合内容。
  6. border-top: 1px solid #ccc;这个属性应该保留
  7. 悬停行突出显示

希望看到的图像:

【问题讨论】:

  • 你的表结构不对,dummies.com/web-design-development/site-development/…不要重复,是表头
  • @Grumpy 如果必须在列位置放置标题怎么办?
  • 禁止。您可以这样做,但 html 将不起作用#easyasthat 否则您需要重新考虑您的解决方案。
  • 如果您上传一张显示所需表格外观的图片,将会非常有帮助。我不完全确定你想要实现什么。
  • @liqSTAR - 禁止什么? &lt;th&gt; 沿列的元素?这正是scope=row 的意义所在。

标签: html css html-table css-position absolute


【解决方案1】:

恐怕没有完美的解决方案。

我会给你不同的选择,你需要决定放弃什么。


绝对定位的列。

✅ 纯 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>

最后的笔记

由您决定哪种方法最适合您的需求。

就我个人而言,我认为第四个最强大,因为:

  • 如果 JS 被禁用,列将折叠超过最佳点,但一切都会正常工作。只需使用 CSS 中的默认 left 属性即可。

  • 在 IE11 下,表格会很好地退回到非固定列表格。

我认为这没什么大不了的。当然,如果您正在为使用 IE11 为首选浏览器的 Intranet 进行编程,请采用第一种或第二种方法。

【讨论】:

  • 哦,非常感谢!真的很酷!有position: absolute 的解决方案真的很棒。您可以添加一个类来突出显示悬停的行吗?
  • 大卫,我只有一个问题。当我突出显示行时,某些带有position: absolute 的列的突出显示方式与可滚动的列不同。是否可以解决此问题?
  • 大卫我只是想知道是否可以制作前三列position: absolute,但不设置硬编码width
  • 关于突出显示,这是固定列的已知问题,也是我使用tr:hover td {...} 而不是更直截了当的tr:hover {...} 的原因。关于position: absolute 没有硬编码width 恐怕这是不可能的。反正我现在在逃,等我回来看看这两样东西。
  • @Learner - 谢谢你的话。你也有美好的一天!
【解决方案2】:

您应该改用粘性单元格,这会将列保留为文档流的一部分。此外,如果您希望列对内容宽度做出反应,您需要删除 table-layout: fixed

如果您愿意,您也可以删除max-width,这是一个示例,可以为列添加一些合理的最大宽度,之后它们将得到一个省略号(参见最后一列)。

.scroller {
  max-width: 600px;
  overflow: auto;
}

table, table * {
  box-sizing: border-box;
}

table {
  width: 100%;
  border-collapse: collapse;
  border-spacing: 0;
}

th {
  text-align: left;
}

/* borders should be on th/td so the table can collapse them */
th, td {
  border-top: 1px solid #ccc;
  padding: 0; /* Default padding should be removed */
}

/* padding, overflow ellipses etc behaves better if
   content is wrapped in an inner element */
.inner-cell {
  background: white;
  padding: 10px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  max-width: 260px;
}

.sticky {
  position: sticky;
  left: 0;
}
.sticky-2 {
  left: 6em;
}
.sticky-3 {
  left: 12em;
}
/* Behaves better if width is set on inner el (or it moves 1px when scrolling) */
.sticky .inner-cell {
  width: 6em;
}
<div class="scroller">
  <table>
    <thead>
      <tr>
        <th class="sticky sticky-1"><div class="inner-cell">Stick 1</div></th>
        <th class="sticky sticky-2"><div class="inner-cell">Stick 2</div></th>
        <th class="sticky sticky-3"><div class="inner-cell">Stick 3</div></th>
        <th><div class="inner-cell">Normal 1</div></th>
        <th><div class="inner-cell">Normal 2</div></th>
        <th><div class="inner-cell">Normal 3</div></th>
      </tr>
    </thead>

    <tbody>
      <tr>
        <td class="sticky sticky-1"><div class="inner-cell">Sticky Val 1</div></td>
        <td class="sticky sticky-2"><div class="inner-cell">Sticky Val 2</div></td>
        <td class="sticky sticky-3"><div class="inner-cell">Sticky Val 3</div></td>
        <td><div class="inner-cell">Sticky Normal 1</div></td>
        <td><div class="inner-cell">Sticky Normal 2 looooong</div></td>
        <td><div class="inner-cell">Sticky Normal 3 something really long we don't want to display all of this</div></td>
      </tr>
    </tbody>
  </table>
</div>

【讨论】:

  • 感谢您的回复!我没有足够的知识来应用您的答案。你能把你的样式应用到我的 html 元素上吗?
  • 只是挑剔:使用position: sticky,元素根据文档的正常流程定位直到它越过指定的阈值,此时它被视为固定.不过很好的解决方案。
【解决方案3】:

首先,你在重复使用标签,避免这种情况。 第二件事是设置自动宽度和高度使用

th {
width: auto;
height: auto;
}

【讨论】:

  • 感谢您的回复。但是,如果我设置为auto,则水平滚动条将消失,行将折叠
猜你喜欢
相关资源
最近更新 更多
热门标签