2

I'm creating a table to inspect tabular data (like result of SQL query) and trying to find the optimal layout.

I don't know the number columns or its content, I know only that some columns could be narrow and some wide. And that table should take no more than 100% of its container and columns should not wrap, it's ok to hide overflow. And it should utilise the available space in a reasonable way.

How it could be done? I tried table-layout: fixed (without it table won't respect width: 100% and takes wider space) but the layout din't utilise all the available space (see screenshot below). Are there better ways? Maybe involving some JS calculations (I'm using Svelte)?

enter image description here

One possible improvement would be - if the column is narrow, let it be narrow. But in the example below the narrow column "Aaa" still take the extra space it don't need.

Example:

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

table td {
  white-space:   nowrap;
}

table td {
  overflow:      hidden;
  text-overflow: ellipsis;
}
<html>
<body>

<table>
  <tr>
    <td>Aaa</td>
    <td>Bbb bbb bbb bbb bb bbbbbb bb bbbbbb bb bbbbbb bbbbbbbb bb  bbbbbb bb  bbbbbb bb bbbbbb bb</td>
    <td>Ccc cc c ccccc c cccc</td>
  </tr>

</table>

</body>
</html>

P.S.

Please note the white-space: nowrap; - the solution for the similar question Table overflowing outside of div doesn't work with the white-space: nowrap; option.

Alex Craft
  • 13,598
  • 11
  • 69
  • 133
  • You definitely do not want `table-layout:fixed` as this will make your columns be of equal width. If you just set the layout to auto and the width to 100% you should have what you want. – Ant Jun 12 '21 at 23:26
  • 1
    @Ant without `table-layout:fixed` the table won't respect the `width: 100%` and takes more space than its parent container. – Alex Craft Jun 12 '21 at 23:29
  • 1
    Oh, that changes things... You practically want the auto layout but within a parent's width, which I'm quite sure is not possible without either some hard limits on the width of the table or a bunch of calculations in javascript. You should also take a look [here](https://stackoverflow.com/questions/2259189/table-overflowing-outside-of-div) – Ant Jun 12 '21 at 23:35
  • `max-width` instead? – wazz Jun 12 '21 at 23:48
  • Does this answer your question? [Table overflowing outside of div](https://stackoverflow.com/questions/2259189/table-overflowing-outside-of-div) – wazz Jun 12 '21 at 23:51
  • @wazz no it doesn't work with `white-space: nowrap;` the table gets out of its container. – Alex Craft Jun 13 '21 at 00:04

1 Answers1

2

You'll need a little JavaScript to have a fixed table at 100% with truncated content and no overflow. table-layout: fixed is useless unless you explicitly set column widths and since the number of columns are variable as well as length of cell content, the most efficient way to handle it is by ensuring each column is of equal width.

  1. Use the table rows cells collection properties to get the number of <td> in a <tr>
const numberOfColumns = table.rows[0].cells.length;
  1. Then divide 100 by the number of columns
let columnWidth = `${100 / numberOfColumns}%`;
  1. Apply that number as a percentage width to each <td> of the first <tr>
[...table.rows[0].cells].forEach(td => td.style = columnWidth);

Note: The first example does not adjust for empty cells because it's pointless when you have more than one row. Example 2 is added to show how to adjust for empty cells (not recommended for tables with multiple rows). Basically it assigns 1% width to each column then assigns the following percentage width to each <td> that has text (keeps track by index number):

arrayOfIndices.forEach(index => table.rows[0].cells[index].style.width = `${(100 - numberOfEmpty)/arrayOfIndices.length}%`);

Example 1

const table = document.querySelector('table');
const columns = table.rows[0].cells.length;
[...table.rows[0].cells].forEach(td => td.style = `${100/columns}%`);
table {
  width: 100%;
  table-layout: fixed;
}

td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
<main>
  <table>
    <tr>
      <td>xxxxxxxxxxxx</td>
      <td>xxxxxxxxxxxx</td>
      <td>xxxxxxxxxxxx</td>
      <td>xxxxxxxxxxxx</td>
      <td>xxxxxxxxxxxx</td>
      <td>xxxxxxxxxxxx</td>
      <td>xxxxxxxxxxxx</td>
      <td>xxxxxxxxxxxx</td>
    </tr>
  </table>
</main>

Note: <td>s have an alternating background color. The empty cells are at 1% width (2nd and 5th cells).

Example 2

const table = document.querySelector('table');
const columns = table.rows[0].cells.length;
const fullCells = [...table.rows[0].cells].flatMap((td, idx) => td.textContent.length > 0 ? [idx] : []); 
const newWidth = 100 - (columns - fullCells.length);
[...table.rows[0].cells].forEach(td => td.style.width = '1%');
fullCells.forEach(index => table.rows[0].cells[index].style.width = `${newWidth/fullCells.length}%`);
table {
  width: 100%;
  table-layout: fixed;
}

td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

td:nth-child(odd) {
  background: tomato;
}

td:nth-child(even) {
  background: cyan;
}
<main>
  <table>
    <tr>
      <td>AAAAAAAAAAAA</td>
      <td></td>
      <td>CCCCCCCCCCCCCCCCCCCCCCCCCCCC</td>
      <td>DDDDDDDDDDDDDDDDDDDDDDDDDDDD</td>
      <td></td>
      <td>FFFFFFFFFFFF</td>
      <td>GGGGGGGGGGGG</td>
      <td>HHHHHHHHHHHH</td>
    </tr>
  </table>
</main>
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
zer00ne
  • 41,936
  • 6
  • 41
  • 68