J'essaie d'imbriquer des tables dans une ligne tout en conservant l'apparence d'une seule table, comme illustré dans l'exemple ci-dessous (une table avec une seule ligne avec une valeur de données et deux tables imbriquées, l'une 2x2 et l'autre 3x3):
C'est juste un exemple; la table réelle a beaucoup plus de lignes et de colonnes. Je souhaite utiliser des tableaux en raison de la modification naturelle de la largeur des colonnes et de la hauteur des lignes pour adapter les données du tableau sans avoir à vous soucier de la taille du conteneur (c'est-à-dire la largeur de la table = 100%).
Le problème que j'ai, c'est que le tableau le plus haut définit la hauteur des lignes, mais que les autres tableaux ne se développent pas pour remplir cette hauteur. Par conséquent, les bordures internes ne s'étendent pas de haut en bas, comme le montre le résultat de cet extrait:
.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>
Maintenant, je sais que je peux résoudre ce problème à l’aide de rowspan (et c’est ainsi que je résous actuellement le problème), mais cela nécessite de décider à l’avance des lignes à aligner, ce qui peut entraîner des problèmes tels que ceux générés par l’extrait ci-dessous. serait mieux si j'avais appliqué rowspan="2"
à la première ligne (au lieu de la dernière ligne) de la table avec 2 lignes:
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>
Je préférerais que le tableau ci-dessus ressemble à ceci:
Existe-t-il un moyen de réaliser ce que je veux en utilisant HTML/CSS? Il y a beaucoup de lignes dans la table, donc je préférerais que le navigateur le trie avant le rendu. Cependant, si ce n'est pas possible, je suis ouvert à une solution Javascript/JQuery.
Mettre à jour
Bien que j’ai trouvé une solution viable à l’époque (voir ma réponse publiée), j’ai depuis rencontré quelques situations dans lesquelles il était difficile de définir la largeur des colonnes à l’avance (même sous forme de pourcentages) en raison de l’impossibilité d’anticiper toutes les données possibles. être affichées. J'espère donc trouver une réponse qui ne repose pas sur cela.
Comme je n’ai pas expliqué les choses aussi clairement que je devrais l’être, j’ai plusieurs lignes dans lesquelles je veux imbriquer des tableaux, en gardant les hauteurs égales, ainsi que la largeur des colonnes. Par exemple, pour deux lignes, j'aimerais pouvoir créer une mise en page comme celle-ci:
Où avec un tableau HTML brut le résultat ressemble à ceci:
.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>
Je suggérerais l'utilisation de flex pour répondre à vos besoins. Flex est très puissant pour ce type de mise en page, car nous pouvons facilement laisser le contenu le guider. S'il vous plaît, voir l'extrait ci-joint. Il est purement fait à partir de HTML et de CSS. Pas de taille fixe et pas de Javascript requis.
(ancien extrait)
.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>
Mise à jour : Modifié en fonction de votre commentaire/réponse. Cela dépend un peu de votre structure HTML. Je devais déplacer les en-têtes vers son propre ".row.row-item
" et, par conséquent, je devais définir une base flexible pour aligner les colonnes. Cela peut être étendu avec plusieurs ".row.row-item
". Voir l'extrait ci-dessous.
.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>
J'ai finalement pu résoudre ce problème en écrivant une fonction onload
pour rechercher la hauteur maximale de toutes les tables imbriquées dans une ligne donnée, puis définir la hauteur de chaque table imbriquée dans cette ligne avec la même valeur.
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';
}
};
Le seul inconvénient de cette solution est que cela signifiait que je devais attribuer des largeurs au <td>
s dans les tableaux imbriqués. Cependant, étant donné que je pouvais utiliser des pourcentages de largeur, ce n'était pas un gros problème pour moi:
<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>
Sortie finale:
Cet exemple est une conception sensible qui utilise uniquement du HTML et des grilles CSS imbriquées dans une Flexbox.
J'ai pris la liberté d'ajouter des en-têtes et un espace réservé à la pagination à votre scénario. Ceux-ci peuvent être supprimés sans affecter le reste de la mise en page.
J'ai créé un rapport GitHub nested-CSS-Grid-and-Flexbox-Playground qui contient une application Angular utilisant cette présentation avec des données dynamiques ainsi que des références accumulées lors de la recherche du projet.
<!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>
*, *::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;
}
}
rowspan
s ou colspan
s n'a été endommagé lors de la création de cette tableCe qui suit est un schéma de la table sans thead:
Le terme "colonne" est appelé vaguement. Par exemple: la colonne td.items
fait référence à tous les td.items
en tant que groupe.
Il y a la table principale ...
... et ensuite un tbody pour chaque ligne client. Avoir plusieurs corps est valide.
Suivant est un tr et puis ...
... un td. Ce td correspond aux colonnes: .customer
, .items
et .payments
.
Au sein de chaque td se trouvent un sous-tableau et un sous-corps.
La première colonne td.customer
est limitée à une sous-ligne car le contenu de chaque tbody.row
est juste un nom du client. Les cellules de cette colonne ont les propriétés Qui contrôlent tbody.row
height (Voir les commentaires dans la démo).
td.items
peut avoir plusieurs sous-lignes, les caractéristiques de démonstration allant de 1 à 3 Sous-lignes.td.payments
peut également avoir plusieurs sous-lignes, la démo présentant les caractéristiques 2 sous-lignes chacune.Les détails sont commentés dans la démo
La démonstration est réactive (MQ pour les cas Edge et les appareils mobiles peut être nécessaire).
Valide HTML/CSS et sémantiquement valable.
Pas de JavaScript/jQuery.
Construit uniquement avec les balises <table>
, <thead>
, <tbody>
, <tr>
, <th>
et <td>
(même pas une div ou une étendue).
* { 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 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>
Voici une solution JavaScript qui définit automatiquement la hauteur des lignes et la largeur des colonnes (sans spécifier la largeur des colonnes), et prend en charge le redimensionnement.
La solution complète/démo est ici: http://jsfiddle.net/ez0jqc1L/
Le seul inconvénient est que vous devez envelopper le contenu de toutes les cellules <td>
avec <div class="content"></div>
(voir le jsfiddle pour un exemple).
Tout d'abord, nous corrigeons les hauteurs de sous-table:
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';
}
}
Ensuite, nous parcourons toutes les colonnes de sous-tables pour calculer la largeur maximale de chaque ensemble de cellules adjacentes verticalement (nous la stockons dans le tableau maxColWidths
, chaque index du tableau correspond à l'ensemble de cellules adjacentes verticalement):
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]);
}
});
Enfin, nous définissons les largeurs de colonne. C’est ici que l’emballage <div class="content">
est requis, car définir la largeur d’un <td>
ne garantit pas que le navigateur lui donnera cette largeur exacte, mais je peux avoir cette garantie avec un élément ayant display: inline-block
.
forEachSubtableColumn(function(c, td) {
td.children[0].style.width = maxColWidths[c] + 'px';
});
Pour le support de redimensionnement, nous effaçons toutes les largeurs et hauteurs forcées afin de pouvoir les recalculer par la suite:
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();
};
EDIT: Corrigé le code onresize
.
Les tableurs en ligne tels que Google Sheets donnent l’impression si facile, mais lors de ma première plongée, c’était beaucoup plus compliqué. J'ai attribué à chaque ligne un attribut spécial tel que row = "r_1" et à chaque attribut spécifique de subrow tel que row = "r_1" subrow = "sr_1_a". onkeyup events ou un mathématique déclenché par onload pour trouver toutes les lignes parent à l'aide de querySelectorAll, puis s'est assuré que leur hauteur était égale à toutes les hauteurs de subrow ajoutées.
La signification de la balise <table>
a changé entre le HTML actuel et le HTML précédent. Alors que <table>
servait plus d’une fonction de formatage, en HTML5, il ne devrait être utilisé que pour un tableau littéral. Comme d'autres l'ont mentionné, votre configuration ne ressemble pas vraiment à une table au sens littéral. Ainsi, bien que l’utilisation d’un ensemble d’éléments <table>
imbriqués puisse permettre d’obtenir ce que vous voulez, ce n’est probablement pas le moyen le plus efficace.
Pour ce faire, vous pouvez simplement imbriquer un groupe d’éléments <div>
avec des CSS élémentaires. Voici un exemple:
<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>
Cela produira les parties X, Y et Z de l'affichage que vous décrivez ci-dessus. La même technique peut être étendue pour construire le reste de votre affichage.
Quelques points à noter:
J'espère que cela t'aides.