Search code examples
csshtml-tablecss-tables

CSS table with fixed column widths and max height


I'm trying to create a table with fixed column widths, and also a fixed maximum height, which scrolls beyond the maximum height.

Reading around, I would use table-layout:fixed and specify the column widths to accomplish the first task. I would set max-height, overflow:auto and display:block on the table to accomplish the second.

However, these don't seem to be working together. The columns are approximately half of the intended width.

My attempt: https://jsfiddle.net/d3y5g9fq/

<table>
<colgroup>
  <col style="width: 30%">
  <col style="width: 50%">
  <col style="width: 20%">
</colgroup>
<thead>
  <tr>
    <th>Col A</th>
    <th>Col B</th>
    <th>Col C</th>
  </tr>
</thead>
<tbody>
  <tr><td>1</td><td>2</td><td>3</td></tr>
</tbody>
</table>
table {
  table-layout: fixed;
  display: block;
  max-height: 100px;
  overflow: auto;
}

Solution

  • If you change the column widths from percentages to viewport width (vw) it should work as intended, but not quite as expected. Viewport sizes are supposed to size it according to the size of the full viewport, but if you wrap it in a div with a width of 70%, it will work like a percentage instead of a vw in this scenario.

    Using vw with a parent width of 100%:

    table {
      table-layout: fixed;
      display: block;
      max-height: 100px;
      overflow: auto;
    }
    
    p {
      background-color: blue;
      width: 100%;
    }
    
    table, td, th {
      text-align: center;
      border: 1px solid black;
    }
    <p>Hi! </p>
    <table>
    <colgroup>
      <col style="width: 30vw">
      <col style="width: 50vw">
      <col style="width: 20vw">
    </colgroup>
    <tbody>
      <tr>
        <th>Col A</th>
        <th>Col B</th>
        <th>Col C</th>
      </tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
    </tbody>
    </table>

    Using vw with a parent width of 70%:

    table {
      table-layout: fixed;
      display: block;
      max-height: 100px;
      overflow: auto;
    }
    
    p {
      background-color: blue;
      width: 100%;
    }
    
    table, td, th {
      text-align: center;
      border: 1px solid black;
    }
    <p>Hi! </p>
    <div style="width: 70%">
    <table>
    <colgroup>
      <col style="width: 30vw">
      <col style="width: 50vw">
      <col style="width: 20vw">
    </colgroup>
    <tbody>
      <tr>
        <th>Col A</th>
        <th>Col B</th>
        <th>Col C</th>
      </tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
    </tbody>
    </table>
    <div>

    Not quite what you would expect... why? There are a very tiny amount of scenarios where vw and vh do not work as intended. I've never quite found out why myself, but I would guess it is misinterpreting the viewport as a single element for some reason.

    If you want to be syntactically correct, you could also use em instead of vw, which will give you the exact same results:

    Using em with a parent width of 100%:

    table {
      table-layout: fixed;
      display: block;
      max-height: 100px;
      overflow: auto;
    }
    
    p {
      background-color: blue;
      width: 100%;
    }
    
    table, td, th {
      text-align: center;
      border: 1px solid black;
    }
    <p>Hi! </p>
    <table>
    <colgroup>
      <col style="width: 30em">
      <col style="width: 50em">
      <col style="width: 20em">
    </colgroup>
    <tbody>
      <tr>
        <th>Col A</th>
        <th>Col B</th>
        <th>Col C</th>
      </tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
    </tbody>
    </table>

    Using em with a parent width of 70%:

    table {
      table-layout: fixed;
      display: block;
      max-height: 100px;
      overflow: auto;
    }
    
    p {
      background-color: blue;
      width: 100%;
    }
    
    table, td, th {
      text-align: center;
      border: 1px solid black;
    }
    <p>Hi! </p>
    <div style="width: 70%">
    <table>
    <colgroup>
      <col style="width: 30em">
      <col style="width: 50em">
      <col style="width: 20em">
    </colgroup>
    <tbody>
      <tr>
        <th>Col A</th>
        <th>Col B</th>
        <th>Col C</th>
      </tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
      <tr><td>1</td><td>2</td><td>3</td></tr>
    </tbody>
    </table>
    <div>