【问题标题】:Matching table height for nested HTML tables嵌套 HTML 表格的匹配表格高度
【发布时间】:2019-03-01 02:46:50
【问题描述】:

我正在尝试将表格嵌套在表格行中,同时保持单个表格的外观,如下面的示例所示(一个带有数据值的单行表格和两个嵌套表格,一个 2x2,另一个3x3) :

这只是一个例子;实际表有更多的行和列。我想使用表格,因为列宽和行高的自然重排以适应表格数据,而不必担心容器大小(即表格宽度 = 100%)。

我遇到的问题是最高的表设置了行高,但其他表没有扩展以填充该高度,因此内部边框不会从上到下延伸,如结果所示sn-p:

.display {
	border-collapse: collapse;
}
.display, .display td, .display th {
	border: 1px solid black;
}
.subtable {
	border-collapse: collapse;
}
.subtable td {
	border-top: 0;
	border-bottom: 1px solid black;
	border-left: 0;
	border-right: 1px solid black;
}
.subtable tr td:last-of-type {
	border-top: 0;
	border-bottom: 1px solid black;
	border-left: 0;
  border-right: 0;
}
.subtable tr:last-of-type td {
	border-top: 0;
	border-bottom: 0;
	border-left: 0;
	border-right: 1px solid black;
}
.subtable tr:last-of-type td:last-of-type {
	border: 0;
}
td {
	padding: 5px;
}
td.d-subtable {
	padding: 0;
}
<table class="display" cellpadding="0">
	<tr><th>Customer</th><th>Items</th><th>Payments</th></tr>
	<tr><td>Customer Name</td>
		<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>Item1</td><td>5</td><td>$400.00</td></tr><tr><td>Item2</td><td>10</td><td>$200.00</td></tr><tr><td>Item3</td><td>2</td><td>$500.00</td></tr></table></td>
		<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>12 Sep 2018</td><td>$3,000.00</td></tr><tr><td>18 Sep 2018</td><td>$2,000.00</td></tr></table></td>
	</tr>
</table>

现在我知道我可以使用 rowspan 解决这个问题(这就是我目前解决问题的方法),但这需要提前决定要排列哪些行,这可能会导致诸如以下 sn 产生的问题-p,如果我将rowspan="2" 应用于具有 2 行的表的第一行(而不是最后一行)显然会更好:

td {
  border: 1px solid black;
}

table {
  border-collapse: collapse;
  width: 500px;
}
<table cellpadding="5">
	<tr><td rowspan="3">x</td>
		<td>problem when you have some really long text in the first row</td><td>p</td><td>a</td><td>b</td><td>c</td></tr><tr><td rowspan="2">z</td><td rowspan="2">q</td><td>d</td><td>e</td><td>f</td></tr><tr><td>g</td><td>some other really long text</td><td>i</td>
  </tr>
</table>

我希望上表看起来像这样:

有没有办法使用 HTML/CSS 实现我想要的?表中有很多行,所以我希望浏览器在渲染之前对其进行排序。但是,如果不可能,我愿意接受 Javascript/JQuery 解决方案。

更新

虽然我当时确实找到了一个可行的解决方案(请参阅我发布的答案),但我遇到了一些情况,由于无法预测所有的可能显示的数据。所以我希望找到一个不依赖于这样做的答案。

由于我没有说得那么清楚,因此我有多个要在其中嵌套表格的行,以保持高度和列宽匹配。例如,对于两行,我希望能够创建这样的布局:

原始表格 HTML 的结果如下所示:

		.display {
			border-collapse: collapse;
		}
		.display, .display td, .display th {
			border: 1px solid black;
		}
		.subtable {
			border-collapse: collapse;
		}
		.subtable td {
			border-top: 0;
			border-bottom: 1px solid black;
			border-left: 0;
			border-right: 1px solid black;
		}
		.subtable tr td:last-of-type {
			border-top: 0;
			border-bottom: 1px solid black;
			border-left: 0;
			border-right: 0;
		}
		.subtable tr:last-of-type td {
			border-top: 0;
			border-bottom: 0;
			border-left: 0;
			border-right: 1px solid black;
		}
		.subtable tr:last-of-type td:last-of-type {
			border: 0;
		}
		td {
			padding: 5px;
		}
		td.d-subtable {
			padding: 0;
		}
<table class="display" cellpadding="0">
	<tr><th>Customer</th><th>Items</th><th>Payments</th></tr>
	<tr><td>Customer 1</td>
		<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>Item1</td><td>5</td><td>$400.00</td></tr><tr><td>Item2</td><td>100</td><td>$20.00</td></tr><tr><td>Item3</td><td>2</td><td>$500.00</td></tr></table></td>
		<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>12 Sep 2018</td><td>$3,000.00</td></tr><tr><td>18 Sep 2018</td><td>$2,000.00</td></tr></table></td>
	</tr>
	<tr><td>Customer 304</td>
		<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>Item4</td><td>5</td><td>$6.00</td></tr></table></td>
		<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>20 Sep 2018</td><td>$4.00</td></tr><tr><td>27 Sep 2018</td><td>$26.00</td></tr></table></td>
	</tr>
</table>

【问题讨论】:

  • 您的格式似乎没有显示数据表。相反,您似乎只想在某种自定义网格中可视化数据。如果它在语义上不是表格,我不建议使用 &lt;table&gt; 来尝试解决此问题。
  • @zzzzBov 我确实有一个数据表。列和行比我在示例中显示的要多得多;我只是想创建一个演示我遇到的问题的最小示例。我想使用表格,因为它能够重排列宽和行高以使数据适合容器。
  • 我认为更适合您的情况的解决方案是使用 CSS Grid 而不是表格。它会给你更多的控制权。

标签: javascript jquery html css html-table


【解决方案1】:

我建议使用 flex 来满足您的需求。 Flex 对于这种布局非常强大,因为我们可以轻松地让内容引导它。请参阅随附的 sn-p。它纯粹由 HTML 和 CSS 制成。没有固定大小,也不需要 Javascript。

(旧的 sn-p)

.outer {
  display: flex;
  flex-wrap: wrap;
  
  /* For demo purposes */
  max-width: 500px; 
  margin: 20px auto; 
  border-left: 1px solid black;
  border-top: 1px solid black;
}

.column {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
}

.row {
  display: flex;
  flex-direction: row;
  flex: 1 1 auto;
}

.inner {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.item {
  border-right: 1px solid black;
  border-bottom: 1px solid black;
  text-align: center;
  padding: 3px;
}

.item.heading {
  font-weight: bold;
}

.item:not(.heading) {
  flex: 1 1 auto;
  justify-content: center;
  align-items: center;
  display: flex;
}

.fixed .narrow {
  flex-basis: 20px;
}
<div class="outer">
  <div class="column">
    <div class="item heading">Customer</div>
    <div class="item">
      <span>Customer Name</span>
    </div>
  </div>
  <div class="column">
    <div class="item heading">Items</div>
      <div class="inner fixed">
        <div class="row">
          <div class="item">Item1</div>
          <div class="item narrow">5</div>
          <div class="item last">$400.00</div>
        </div>
        <div class="row">
          <div class="item">Item2</div>
          <div class="item narrow">10</div>
          <div class="item last">$200.00</div>
        </div>
        <div class="row">
          <div class="item">Item3</div>
          <div class="item narrow">2</div>
          <div class="item last">$500.00</div>
        </div>
    </div>
  </div>
  <div class="column">
    <div class="item heading">Payments</div>
    <div class="inner">
      <div class="row">
        <div class="item">12 sep 2018</div>
        <div class="item">$3,000.00</div>
      </div>
      <div class="row">
        <div class="item">
          18 sep 2018
        </div>
        <div class="item">
          $2,000.00
        </div>
      </div>
    </div>
  </div>
</div>

更新:根据您的评论/答案进行了更改。这在某种程度上取决于您的 HTML 结构。我不得不将标题移动到它自己的“.row.row-item”,因此需要设置一个 flex-basis 来对齐列。这可以用多个“.row.row-item”扩展。请参阅下面的 sn-p。

.outer {
  display: flex;
  flex-wrap: wrap;
  
  /* For demo purposes */
  max-width: 600px; 
  margin: 20px auto; 
  border-left: 1px solid black;
  border-top: 1px solid black;
}

.column {
  flex: 1 1 33.33%;
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
}

.row {
  display: flex;
  flex-direction: row;
  flex: 1 1 auto;
}

.row-item {
  flex-basis: 100%;
}

.inner {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.item {
  border-right: 1px solid black;
  border-bottom: 1px solid black;
  text-align: center;
}

.item.heading {
  font-weight: bold;
  flex: 1 1 33.33%;
}

.item:not(.heading) {
  flex: 1 1 33.33%;
  justify-content: center;
  align-items: center;
  display: flex;
}

.fixed .narrow {
  flex: 1 1 20px;
}
<div class="outer">
  <div class="row row-item">
    <div class="item heading">Customer</div>
    <div class="item heading">Items</div>
    <div class="item heading">Payments</div>
  </div>
  <div class="row row-item">
    <div class="column">
      <div class="item">
        <span>Customer 1</span>
      </div>
    </div>
    <div class="column">
        <div class="inner fixed">
          <div class="row">
            <div class="item">Item1</div>
            <div class="item narrow">5</div>
            <div class="item last">$400.00</div>
          </div>
          <div class="row">
            <div class="item">Item2</div> 
            <div class="item narrow">10</div>
            <div class="item last">$200.00</div>
          </div>
          <div class="row">
            <div class="item">Item3</div>
            <div class="item narrow">2</div>
            <div class="item last">$500.00</div>
          </div>
      </div>
    </div>
    <div class="column">
      <div class="inner">
        <div class="row">
          <div class="item">12 sep 2018</div>
          <div class="item">$3,000.00</div>
        </div>
        <div class="row">
          <div class="item">
            18 sep 2018
          </div>
          <div class="item">
            $2,000.00
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="row row-item">
    <div class="column">
      <div class="item">
        <span>Customer 304</span>
      </div>
    </div>
    <div class="column">
        <div class="inner fixed">
          <div class="row">
            <div class="item">Item4</div>
            <div class="item narrow">5</div>
            <div class="item last">$6.00</div>
          </div>
      </div>
    </div>
    <div class="column">
      <div class="inner">
        <div class="row">
          <div class="item">20 sep 2018</div>
          <div class="item">$4.00</div>
        </div>
        <div class="row">
          <div class="item">
            27 sep 2018
          </div>
          <div class="item">
            $26.00
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="row row-item">
    <div class="column">
      <div class="item">
        <span>Customer 605</span>
      </div>
    </div>
    <div class="column">
        <div class="inner fixed">
          <div class="row">
            <div class="item">Item5</div>
            <div class="item narrow">50</div>
            <div class="item last">$60.00</div>
          </div>          
          <div class="row">
            <div class="item">Item6</div>
            <div class="item narrow">3</div>
            <div class="item last">$260.00</div>
          </div>
      </div>
    </div>
    <div class="column">
      <div class="inner">
        <div class="row">
          <div class="item">29 sep 2018</div>
          <div class="item">$40.00</div>
        </div>
        <div class="row">
          <div class="item">
            30 sep 2018
          </div>
          <div class="item">
            $206.00
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

【讨论】:

  • 这看起来很有希望。您能告诉我如何按照我发布的答案将其扩展到多行吗?
  • 另请参阅我对问题的更新。我希望这可以使问题更加清晰。
  • @Nick 相应更新。现在支持多个项目行。
  • 这是一个使用嵌套(一维)Flexbox 容器的巧妙实现。但是,当我缩小浏览器大小或将视口设置为三星 S9 大小(使用 Firefox DevTools)时,列没有正确排列。您是否考虑过使用二维 CSS 网格容器?
  • @RandyDaddis 您是否有机会按照这些思路发布答案以便我进行评估?
【解决方案2】:

我最终能够通过编写一个onload 函数来解决这个问题,该函数可以找到给定行中所有嵌套表的最大高度,然后将该行中每个嵌套表的高度设置为相同的值。

window.onload=function () {
    let rows = document.querySelectorAll('tr');
    for (let r = 0; r < rows.length; r++) {
        let subtables = rows[r].querySelectorAll('.subtable');
        let maxHeight = 0;
        for (let i = 0; i < subtables.length; i++) {
            maxHeight = Math.max(maxHeight, subtables[i].clientHeight);
        }
        for (let i = 0; i < subtables.length; i++) subtables[i].style.height='' + maxHeight + 'px';
    }
};

这个解决方案的唯一缺点是它意味着我必须为嵌套表中的&lt;td&gt;s 分配宽度。但是,由于我可以使用百分比宽度,这对我来说不是太大的问题:

<table class="display" cellpadding="0">
    <tr><th>Customer</th><th>Items</th><th>Payments</th></tr>
    <tr><td>Customer 1</td>
        <td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td width="35%">Item1</td><td width="20%">5</td><td width="45%">$400.00</td></tr><tr><td>Item2</td><td>10</td><td>$200.00</td></tr><tr><td>Item3</td><td>2</td><td>$500.00</td></tr></table></td>
        <td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td width="60%">12 Sep 2018</td><td width="40%">$3,000.00</td></tr><tr><td>18 Sep 2018</td><td>$2,000.00</td></tr></table></td>
    </tr>
    <tr><td>Customer 2</td>
        <td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td width="35%">Item4</td><td width="20%">5</td><td width="45%">$600.00</td></tr></table></td>
        <td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td width="60%">20 Sep 2018</td><td width="40%">$4,000.00</td></tr><tr><td>27 Sep 2018</td><td>$2,000.00</td></tr></table></td>
    </tr>
</table>

最终输出:

【讨论】:

    【解决方案3】:

    此示例是一个响应式设计,它仅使用 HTML 和 Flexbox 内的嵌套 CSS 网格。

    我冒昧地为您的场景添加了标题和分页占位符。这些可以被删除而不影响布局的其余部分。

    我创建了一个 GitHub 存储库 nested-CSS-Grid-and-Flexbox-Playground,其中包含一个 Angular 应用程序,该应用程序利用此布局和动态数据以及我在研究此项目时积累的参考资料。

    HTML

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8" />
      <title></title>
    </head>
    <body>
      <div class="container">
        <div class="header">
          <h1>Customers List</h1>
        </div>
        <div class="list">
          <div class="customer-column-header">Customers</div>
          <div class="invoice-column-header">Invoices</div>
          <div class="payments-column-header">Payments</div>
          <div class="customer-row">
            <div class="customer-column">
              <div>Acme Widget Manufacturing, Inc.</div>
            </div>
            <ul class="invoice-column">
              <li class="invoice-row-header">
                <div>Description</div>
                <div>Quantity</div>
                <div>Price</div>
              </li>
              <li class="invoice-row">
                <div>Item 1</div>
                <div>5</div>
                <div>$400.00</div>
              </li>
              <li class="invoice-row">
                <div>Item 2</div>
                <div>10</div>
                <div>$200.00</div>
              </li>
              <li class="invoice-row">
                <div>Item 3</div>
                <div>2</div>
                <div>$500.00</div>
              </li>
            </ul>
            <ul class="payment-column">
              <li class="payment-row-header">
                <div>Date</div>
                <div>Amount</div>
              </li>
              <li class="payment-row">
                <div>12 Sep 2018</div>
                <div>$3,000.00</div>
              </li>
              <li class="payment-row">
                <div>18 Sep 2018</div>
                <div>$2,000.00</div>
              </li>
              <li class="payment-row">
                <div>12 Sep 2018</div>
                <div>$3,000.00</div>
              </li>
              <li class="payment-row">
                <div>18 Sep 2018</div>
                <div>$2,000.00</div>
              </li>
            </ul>
          </div>
          <div class="customer-row">
            <div class="customer-column">
              <div>Beta Company</div>
            </div>
            <ul class="invoice-column">
              <li class="invoice-row-header">
                <div>Description</div>
                <div>Quantity</div>
                <div>Price</div>
              </li>
              <li class="invoice-row">
                <div>Item 1</div>
                <div>5</div>
                <div>$400.00</div>
              </li>
              <li class="invoice-row">
                <div>Item 2</div>
                <div>10</div>
                <div>$200.00</div>
              </li>
              <li class="invoice-row">
                <div>Item 3</div>
                <div>2</div>
                <div>$500.00</div>
              </li>
            </ul>
            <ul class="payment-column">
              <li class="payment-row-header">
                <div>Date</div>
                <div>Amount</div>
              </li>
              <li class="payment-row">
                <div>12 Sep 2018</div>
                <div>$3,000.00</div>
              </li>
              <li class="payment-row">
                <div>18 Sep 2018</div>
                <div>$2,000.00</div>
              </li>
            </ul>
          </div>
        </div>
        <div class="pagination">
          <p>Pagination Placeholder</p>
        </div>
      </div>
    </body>
    </html>
    

    CSS

    *, *::before, *::after {
      margin: 0;
      padding: 0;
      box-sizing: inherit;
    }
    
    ul {
      list-style-type: none;
    }
    
    .container {
      width: 62.5rem;
      max-width: 80rem;
      margin: 0 auto;
      background-color: lightgray;
      display: flex;
      flex-direction: column;
      justify-content: center;
    }
    
    .header {
      padding: .5rem;
      background-color: darkgrey;
      align-self: center;
    }
    
    .list {
      background-color: darkcyan;
      display: grid;
      grid-template-columns: 1fr repeat(2, minmax(min-content, 1fr));
    }
    
    .customer-column-header {
      grid-column: 1 / 2;
    }
    
    .invoice-column-header {
      grid-column: 2 / 3;
    }
    
    .payments-column-header {
      grid-column: 3 / 4;
    }
    
    .customer-column-header,
    .invoice-column-header,
    .payments-column-header {
      padding: .5rem;
      text-align: center;
    }
    
    .customer-row {
      border-left: 1px solid;
      border-top: 1px solid;
      background-color: orangered;
      grid-column: 1 / -1;
      display: grid;
      grid-template-columns: 1fr repeat(2, minmax(min-content, 1fr));
    }
    
    .customer-column {
      grid-column: 1 / 2;
    }
    
    .invoice-column {
      grid-column: 2 / 3;
    }
    
    .payment-column {
      grid-column: 3 / 4;
    }
    
    .customer-column {
      align-self: center;
      justify-self: right;
    }
    
      .customer-column > div {
        padding: 1rem;
      }
    
    .invoice-column {
      border-left: 1px solid;
    }
    
    .invoice-row-header {
      background-color: darkcyan;
      border-bottom: 1px solid;
      display: grid;
      grid-template-columns: repeat(3, minmax(6rem, 1fr));
      justify-self: stretch;
    }
    
      .invoice-row-header > div {
        text-align: right;
        padding: .5rem;
        justify-self: stretch;
        align-self: stretch;
      }
    
        .invoice-row-header > div:nth-child(2) {
          border-left: 1px solid;
          border-right: 1px solid;
        }
    
    .invoice-row {
      border-bottom: 1px solid;
      display: grid;
      grid-template-columns: repeat(3, minmax(6rem, 1fr));
      justify-items: stretch;
      align-items: stretch;
    }
    
      .invoice-row > div {
        text-align: right;
        padding: .5rem;
        justify-self: stretch;
        align-self: stretch;
      }
    
      .invoice-row div:nth-child(2) {
        border-left: 1px solid;
        border-right: 1px solid;
      }
    
    .payment-column {
      border-left: 1px solid;
    }
    
    .payment-row-header {
      background-color: darkcyan;
      border-bottom: 1px solid;
      display: grid;
      grid-template-columns: repeat(2, minmax(6rem, 1fr));
      justify-self: stretch;
    }
    
      .payment-row-header > div {
        text-align: right;
        padding: .5rem;
        justify-self: stretch;
        align-self: stretch;
      }
    
        .payment-row-header > div:nth-child(1) {
          border-right: 1px solid;
        }
    
    .payment-row {
      border-bottom: 1px solid;
      display: grid;
      grid-template-columns: repeat(2, minmax(6rem, 1fr));
      justify-items: stretch;
      align-items: stretch;
    }
    
      .payment-row > div {
        text-align: right;
        padding: .5rem;
        justify-self: stretch;
        align-self: stretch;
      }
    
        .payment-row > div:nth-child(1) {
          border-right: 1px solid;
        }
    
    .pagination {
      padding: .5rem;
      background-color: darkgrey;
      align-self: center;
    }
    
    @media only screen and (min-width: 120rem) {
    
      .container {
        max-width: 80rem;
        margin: 0;
      }
    }
    
    @media only screen and (max-width: 80rem) {
    
      .container {
        max-width: 62.5rem;
        margin: 0 auto;
      }
    }
    
    @media only screen and (max-width: 62.5rem) {
    
      .container {
        max-width: 45rem;
        margin: 0 auto;
      }
    
      .list {
        grid-template-columns: repeat(autofit, 100%);
      }
    
      .customer-column-header,
      .invoice-column-header,
      .payments-column-header {
        grid-column: 1 / -1;
      }
    
      .customer-row {
        grid-template-columns: repeat(autofit, 100%);
        justify-content: center;
      }
    
        .customer-row .customer-column,
        .customer-row .invoice-column,
        .customer-row .payments-column {
          grid-column: 1 / -1;
        }
    
      .customer-column {
        justify-self: center;
      }
    }
    
    @media only screen and (max-width: 45rem) {
    
      .container {
        width: 100%;
        margin: 0 auto;
      }
    }
    

    cref:https://codepen.io/randydaddis/pen/LqEjEg

    【讨论】:

    • 谢谢你 - 我有很多不熟悉的 css 属性。是时候做一些研究了...
    • Advanced CSS and Sass: Flexbox, Grid, Animations and More 是一个 28 小时的课程,有深入的讲座,值得考虑。
    • 最新的更新看起来不错 - 有没有办法让子网格的高度匹配?
    • 我尝试使用修改后的代码修改您的 codepen,但它似乎并没有扩展支付网格...
    • 也许你正在寻找一个实验性的分叉。我取下了那个叉子。发票和付款栏的黄色背景显示在行数较少的列上。发票和付款栏延伸到客户行。问题是将发票或付款行列表中较短的一个延伸到其父列。从理论上讲,这应该可行,但我还没有弄清楚。如果您在发票和付款列中剪切或复制/粘贴行,您应该会在列底部看到黄色背景,并且行数较少。它出现在底部是因为列项与列顶部对齐。
    【解决方案4】:

    没有rowspans 或colspans 在制作这张桌子时受到伤害

    以下是无thead的表格示意图:

    术语“列” 被称为松散的术语。例如:列td.items 指所有 td.items 作为一个组。

    1. 有主表...

    2. ...然后是每个客户行的 tbody。拥有多个 tbody 是有效的。

    3. 接下来是一个 tr 然后...

    4. ...一个 td。此 td 是列:.customer.items.payments

    5. 在每个 td 中都有一个子表和子体。

    6. 第一列td.customer 被限制为一个子行,因为每个子行的内容 tbody.row 只是一个 客户的姓名。此列的单元格具有属性 那个控制tbody.row高度 (参见演示中的 cmets)。

    7. 第二列td.items可以有多个子行,demo features从1到3 子行。
    8. 最后一列td.payments也可以有多个子行,演示功能 每个 2 个子行。

    演示

    详情在demo中注释

    • 演示是响应式的(可能需要 MQ 用于边缘案例和移动设备)。

    • 有效的 HTML/CSS 和语义合理。

    • 没有 JavaScript/jQuery。

    • 纯粹使用 &lt;table&gt;&lt;thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;td&gt; 标签构建(甚至不是 div 或 span)。

    * { border: 0px none transparent; padding: 0px; margin: 0px; }
    
    /* 
    |- table-layout: fixed; 
    || Gives you more control over table behavior such as setting column widths and 
    || table adhering to them.
    ===
    |- height: 100%; width: 100%; 
    || Applied to table.main as well as the nested tables. It facilitates all of 
    || the nested tables to stretch evenly within tbody.row.
    */
    table { border-collapse: collapse; border: 2px solid #000; 
    table-layout: fixed; height: 100%; width: 100%; }
    
    table table { border: 1px solid #000; }
    
    .main { min-height: 40vh; }
    
    th { border-bottom: 2px solid #000; outline: 1px solid #000; }
    
    /*
    || This rule set determines content wrapping behavior within each cell.
    */
    td td { border: 1px solid #000; padding: 0px 5px; word-wrap: break-word; 
    word-break:break-word; overflow: hidden}
    
    .items td:first-of-type { width: 30%; }
    
    .items td:nth-of-type(2) { width: 25%; text-align: right; }
    
    .items td:last-of-type { width: 45%; text-align: right; }
    
    .payments td:last-of-type { text-align: right; }
    
    .customer,
    .items,
    .payments { border: 0px none transparent; padding: 0px; }
    
    th:first-of-type { border-left: 3px solid #000; width: 20%; }
    
    th:nth-of-type(2) { width: 40%; }
    
    th:last-of-type { border-right: 3px solid #000; width: 40%; }
    
    /*
    || This allows the tr.row to always be equal in height as well as being
    || responsive. This column was the best choice as the one to stabilize height 
    || since the content probably changes the least and it has the most space to use
    || hidden spacers (see next comment). 
    */
    .customer table { min-height: 20vh; } 
    
    /*
    || This sets a &nbsp; within the cells in the first column. Although vh units
    || are very responsive, they will start collapsing if the viewport height is 
    || reduced disproportionately vs. viewport width. Thus, this pseudo-element
    || ensures a minimum height of 60px for both tr.row.
    */
    .customer td::after { content: '\a0'; display: inline-block; width:0.5px; 
    min-height: 60px; line-height: 60px; vertical-align: middle; }
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset='utf-8'>
    </head>
    <body>
    
    <table class='main'>
      <thead>
        <tr>
          <th>Customer</th><th>Items</th><th>Payments</th>
        </tr>
      </thead>
      <tbody class='row'>
       <tr>
        <td class='customer'>
          <table><tr><td>
          Customer 1
          </td></tr></table>
        </td>
        <td class='items'>
          <table>
            <tr><td>Item1</td><td>5</td><td>$400.00</td></tr>
            <tr><td>Item2</td><td>100</td><td>$20.00</td></tr>
            <tr><td>Item3</td><td>2</td><td>$500.00</td></tr>
         </table>
       </td>
       <td class='payments'>
         <table>
           <tr><td>12 Sep 2018</td><td>$3,000.00</td></tr>
           <tr><td>18 Sep 2018</td><td>$2,000.00</td></tr>
         </table>
       </td>
      </tr>
     </tbody>
     
     <tbody class='row'>
      <tr>
       <td class='customer'>
        <table><tr><td>
          Customer 304
          </td></tr></table>
       </td>
       <td class='items'>
       <table>
         <tr><td>Item4</td><td>5</td><td>$6.00</td></tr>
       </table>
      </td>
      <td class='payments'>
       <table>
         <tr><td>20 Sep 2018</td><td>$4.00</td></tr>
         <tr><td>27 Sep 2018</td><td>$26.00</td></tr>
       </table>
      </td>
     </tr>
    </tbody>
    
     <tbody class='row'>
       <tr>
        <td class='customer'>      
         <table><tr><td>
          Customer 888
          </td></tr></table>
        </td>
        <td class='items'>
         <table>
            <tr><td>Item5</td><td>50</td><td>$100.00</td></tr>
            <tr><td>Item6</td><td>10</td><td>$500.00</td></tr>
         </table>
       </td>
       <td class='payments'>
         <table>
           <tr><td>10 Nov 2018</td><td>$3,000.00</td></tr>
           <tr><td>17 Nov 2018</td><td>$7,000.00</td></tr>
         </table>
       </td>
      </tr>
     </tbody>
    </table>
    
    </body>
    </html>

    参考文献

    table-layout

    vh and vw

    word-wrap: break-word; word-break:break-word;

    :first-/:nth-/:last-of-type

    ::before/after

    【讨论】:

    • 感谢您的回答。我喜欢这样一个事实,即您能够在不使用 javascript 的情况下获得与我相同的结果,但它仍然存在必须指定列宽的问题,这是我试图避免的。
    • @Nick 我可以删除宽度 坏消息:所有列的宽度都是均匀的——好消息:所有三行仍然处于完美且相等的高度。更新了……太对称了
    • 这很奇怪。我猜table-layout: fixed 只是在没有指定宽度的情况下均分。
    【解决方案5】:

    这是一个自动设置行高和列宽的 JavaScript 解决方案(不需要指定列宽),并支持调整大小。

    完整的解决方案/演示在这里:http://jsfiddle.net/ez0jqc1L/

    需要注意的是,这要求您使用 &lt;div class="content"&gt;&lt;/div&gt; 包装所有 &lt;td&gt; 单元格的内容(有关示例,请参见 jsfiddle)。

    首先,我们固定子表的高度:

    let tbody = /* the tbody of the <table> containing subtables we are fixing */;
    for(let r = 0; r < tbody.children.length; r++) {
        let row = tbody.children[r];
        let subtables = row.querySelectorAll('.subtable');
        let maxHeight = 0;
        for(let i = 0; i < subtables.length; i++) {
            maxHeight = Math.max(maxHeight, subtables[i].clientHeight);
        }
        for(let i = 0; i < subtables.length; i++) {
            subtables[i].style.height = maxHeight + 'px';
        }
    }
    

    然后,我们遍历所有子表列以计算每组垂直相邻单元格的最大宽度(我们将其存储到maxColWidths 数组中,数组的每个索引对应于垂直相邻单元格的集合):

    let forEachSubtableColumn = function(f) {
        for(let r = 0; r < tbody.children.length; r++) {
            let row = tbody.children[r];
            let subtables = row.querySelectorAll('.subtable');
            let c = 0;
            for(let i = 0; i < subtables.length; i++) {
                let subtable = subtables[i];
                if(subtable.children.length === 0 || subtable.children[0].children.length === 0) {
                    continue;
                }
                let stbody = subtable.children[0];
                for(let j = 0; j < stbody.children.length; j++) {
                    let srow = stbody.children[j];
                    for(let k = 0; k < srow.children.length; k++) {
                        let td = srow.children[k];
                        f(c + k, td);
                    }
                }
                c += stbody.children[0].children.length;
            }
        }
    };
    let maxColWidths = []; 
    forEachSubtableColumn(function(c, td) {
        if(c >= maxColWidths.length) {
            maxColWidths.push(td.children[0].clientWidth);
        } else {
            maxColWidths[c] = Math.max(td.children[0].clientWidth, maxColWidths[c]);
        }
    });
    

    最后,我们设置列宽。这是需要 &lt;div class="content"&gt; 包装的地方,因为设置 &lt;td&gt; 的宽度并不能保证浏览器会使其具有精确的宽度,但我可以使用具有 display: inline-block 的元素来保证。

    forEachSubtableColumn(function(c, td) {
        td.children[0].style.width = maxColWidths[c] + 'px';
    });
    

    为了支持调整大小,我们清除了所有强制的宽度和高度,以便我们之后可以重新计算它们:

    onresize = function() {
        let tables = document.querySelectorAll('.subtable');
        for(let i = 0; i < tables.length; i++) {
            let table = tables[i];
            table.style.removeProperty('height');
        }
        let tds = document.querySelectorAll('.subtable td');
        for(let i = 0; i < tds.length; i++) {
            let td = tds[i];
            td.children[0].style.removeProperty('width');
        }
        updateTables();
    };
    

    编辑:更正了onresize 代码。

    【讨论】:

    • 感谢您的回答。这看起来很有趣。在您的小提琴中,为项目名称分配了很多空间,导致付款日期和客户名称不必要地包装。有没有办法解决这个问题?
    • @Nick 分配空间的原因是因为我放置的项目名称很长作为测试。解决此问题的一种方法是在项目列上施加最大宽度,如下所示:jsfiddle.net/2tk4r785
    • 虽然我还没有机会完全测试这个(使用一些大表),但它绝对似乎是最可行的答案;我想我可能可以解决必须为某些列指定最大宽度的约束。当然比指定所有列的宽度更容易。谢谢
    • 好吧,由于计划发生了变化,我以前从未有机会对此进行全面测试,但我现在正在开发一个新项目,并且这个项目 - 通过一些小的调整来处理表格标题 - 工作得很好。谢谢!
    【解决方案6】:

    给定的问题实际上可以通过嵌套 CSS grid 布局相当简单地解决。

    (如果有 colspanrowspan 则需要使用对应的 grid-columngrid-row。)

    我简化了 HTML,以便可以更清楚地理解解决方案 - 尽管这失去了表格的语义。

    如果希望维护表格标记,则需要将中间标签(例如 &lt;tr&gt;)设置为 display:contents 以确保它们不会破坏布局(例如 here)。

    /* defining the grid */
    .grid{display:grid;grid-gap:0 0;}
    .grid-2col{grid-template-columns:auto auto;}
    .grid-3col{grid-template-columns:auto auto auto;}
    
    /* making it look like a table. */
    .th{font-weight:bold;}
    .grid>*{
       border:1px solid black;
       padding:5px;}
    
    /* avoiding double borders. */
    
    /* no double top border - first row can be recognized by class .th */
    .grid>*{border-top:none;}
    .th{border-top:1px solid black;}
    
    /* no double side border - first column can be recognized modulo number of columns of grid. */
    .grid>*{border-left:none;}
    .grid-2col>*:nth-child(2n+1){border-left:1px solid black;}
    .grid-3col>*:nth-child(3n+1){border-left:1px solid black;}
       
    /* no padding in nested tables. */
    .grid>.grid{border:none;padding:0px;}
    .grid>.grid>*{border-left:none;border-top:none;}
    <div class="grid grid-3col">
       <span class="th">Customer</span>
       <span class="th">Items</span>
       <span class="th">Payments</span>
       <span>Customer Name</span>
       <div class="grid grid-3col">
          <span>Item1</span>
          <span>5</span>
          <span>$400.00</span>
          <span>Item2</span>
          <span>10</span>
          <span>$200.00</span>
          <span>Item3</span>
          <span>2</span>
          <span>$500.00</span>
       </div>
       <div class="grid grid-2col">
         <span>12 Sep 2018</span>
         <span>$3,000.00</span>
         <span>18 Sep 2018</span>
         <span>$2,000.00</span>
       </div>
    </div>

    【讨论】:

    • 感谢您的支持 - 由于其他承诺,我今天没时间看,但明天会继续。看起来很有希望。
    • 只是快速浏览一下 - 这与 Randy 的答案在您添加另一行时遇到的问题相同(如问题中的最后一个示例),即两个嵌套网格中的列宽不要在行之间排队。
    • 好吧,可以通过只使用一个gridgrid-row 而不是嵌套的来解决这个问题 - 但是不同列的行也会排列起来。 tablegridfloat - rowcolumn 都排成一列(可能跨越多个单元格),或者两者都不是 - 你不能排成一个但不能排另一个。因此,如果您想要一条垂直线穿过,那么您也将获得一条水平线。
    • 所以在问题中引用“我希望上表看起来像这样:”这一行,您可以直接在上方获取图像,但不能在该行下方获取图像(当然,除非,您使用固定/百分比宽度)。
    • 是的,这就是我得出的结论,也是我转向 JS 解决方案来修复渲染后的宽度和高度的原因。这很丑陋,但它确实有效。感谢您的回答,感谢您的努力。
    【解决方案7】:

    &lt;table&gt; 标签的含义在当前 HTML 和旧 HTML 之间发生了变化。虽然&lt;table&gt; 用于提供更多格式化功能,但在 HTML5 中它只应用于文字表。正如其他人所提到的,您的设置看起来并不像字面意义上的表格。因此,虽然使用一堆嵌套的 &lt;table&gt; 元素可以完成你想要的,但这可能不是最有效的方法。

    您可以通过嵌套一堆&lt;div&gt; 元素以及一些基本的CSS 来实现这一点。这是一个例子:

    <div style="width: 1000px; height: 600px; border: 1px solid #000;">
      <div style="width: 100px; height: 600px; display: inline-block; border: 1px solid #000; margin: 0; padding: 0;">X</div>
      <div style="width: 100px; height: 300px; display: inline-block; border: 1px solid #000; margin: 0; padding: 0;">Y</div>
      <div style="width: 100px; height: 300px; display: inline-block; border: 1px solid #000; position: relative; top: 300px; margin: 0; padding: 0; left: -105px;">Z</div>
    </div>
    

    这将生成您上面描述的显示的 X、Y 和 Z 部分。可以扩展相同的技术来构建显示器的其余部分。

    需要注意的几点:

    • 此示例使用 PX 确定宽度,从 CSS 角度来看,这是非常糟糕的做法。它在移动设备上太大而在大型桌面上太小。但是,您可以调整此技术以使用更具适应性的格式。不过,这会增加解决方案的复杂性,因此我选择使用 PX 作为示例。
    • 此示例使用内联 CSS,因为它是显示解决方案的最简单方法。但是,这是非常糟糕的做法,请不要这样做

    希望这会有所帮助。

    【讨论】:

    • 查看我的编辑,我已尝试改进示例并解释我为什么要使用表格。似乎使用&lt;div&gt;s 会使列大小难以随所附数据而变化?
    【解决方案8】:

    像 Google 表格这样的在线电子表格程序让它看起来很简单,但是当我第一次接触时,它要复杂得多。我给每一行一个特殊的属性,如 row="r_1" 和每个子行的特定属性,如 row="r_1" subrow="sr_1_a"。 onkeyup 事件或 onload 触发数学运算以使用 querySelectorAll 查找所有父行,然后确保它们的高度等于所有子行的高度相加。

    【讨论】:

      【解决方案9】:

      在我看来,我认为很难实现你想要的。

      原因:td 嵌套在tr 中,因此任何高度的变化都会影响关联行的高度。

      建议:你可以有五个单独的选项卡或 div 并将它们显示为 inline-block,然后将你的数据放入其中。

      如果你使用这个建议,请先设置一个包含 5 列的 div 并给它一个 0px 的字体大小,然后记得将字体大小更改为对孩子有用的东西。

      【讨论】:

        猜你喜欢
        • 2011-02-07
        • 2015-08-11
        • 2014-11-25
        • 2014-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-31
        • 1970-01-01
        相关资源
        最近更新 更多