匹配嵌套HTML表的表高度

Nic*_*ick 15 html javascript css jquery html-table

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

在此输入图像描述

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

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

.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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在我知道我可以使用rowspan来解决这个问题(这就是我目前正在解决问题的方法)但是这需要事先决定哪些行排成一行,这可能会导致问题,例如下面代码片段生成的问题,它在哪里如果我rowspan="2"用2行应用于表的第一行(而不是最后一行),那显然会更好:

td {
  border: 1px solid black;
}

table {
  border-collapse: collapse;
  width: 500px;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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

在此输入图像描述

有没有办法用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;
		}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

gui*_*ero 10

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

(旧片段)

.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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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

.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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


Nic*_*ick 9

我最终能够通过编写一个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';
    }
};
Run Code Online (Sandbox Code Playgroud)

这个解决方案的唯一缺点是它意味着我必须<td>在嵌套表中为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>
Run Code Online (Sandbox Code Playgroud)

最终输出:

在此输入图像描述


Sas*_*okh 2

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

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

<td>需要注意的是,这要求您将所有单元格的内容包装起来<div class="content"></div>(请参阅 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';
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我们迭代所有子表列以计算每组垂直相邻单元格的最大宽度(我们将其存储到数组中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]);
    }
});
Run Code Online (Sandbox Code Playgroud)

最后,我们设置列宽。这是<div class="content">需要换行的地方,因为设置 a 的宽度<td>并不能保证浏览器将使其达到精确的宽度,但我可以通过具有display: inline-block.

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

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

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();
};
Run Code Online (Sandbox Code Playgroud)

编辑:更正了onresize代码。