Search code examples
htmlcsshtml-tableflexbox

Why does putting a table inside a flex container with align-items: center mess up scrolling on overflow?


I am trying to create a responsive table by letting the table be scrollable in the x-axis. The code below works as I want. However, if I add align-items: center; to the body's styling, the table won't scroll anymore. Why is that, and is there a good way to work around this?

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>

body {
  display: flex;
  flex-flow: column nowrap;
}

table {
  width: 100%;
  border: 1px solid #ddd;
}

div {
  overflow-x:auto;
}

</style>
</head>
<body>

<h2>Responsive Table</h2>
<p>This paragraph should be centred, as well as the table below.</p>

<div>
  <table>
    <tr>
      ...
    </tr>
    ...
  </table>
</div>

</body>
</html>

Here is a js-fiddle: https://jsfiddle.net/p72g5ast/


Solution

  • When you add align-items: center, you are removing the default align-items: stretch. In a column nowrap flexbox, align-items: stretch is essentially the same as width:100% on each of the flex items.

    To get the behavior you want on on the table after adding align-items: center you can add align-self: stretch or width:100% on the tablewrapper.

    The reason scrolls stop happening is that without the stretch/width:100%, the body flexbox asked tablewrapper what width it wanted to be (its max-content), and the tabblewrapper made itself the exact width of its only child (the table) because that's roughly how max-content calculation works when you have one child. So because the tablewrapper and table had exactly the same width, the tablewrapper never had overflow so never showed a scrollbar.

    Now that I added width:100% to the tablewrapper, the flexbox always makes tablewrapper the same width as the flexbox. So when the table is wider than the flexbox/body/screen/tablewrapper, there is overflow and a scrollbar appears.

    <!DOCTYPE html>
    <html>
    <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
    
    body {
      display: flex;
      flex-flow: column nowrap;
      align-items: center;
    }
    
    table {
      border-collapse: collapse;
      border-spacing: 0;
      border: 1px solid #ddd;
      width: 100%;
    }
    
    th, td {
      text-align: left;
      padding: 8px;
    }
    
    tr:nth-child(even){background-color: #f2f2f2}
    
    </style>
    </head>
    
    <body>
    
    <h2>Responsive Table</h2>
    <p>If you have a table that is too wide, you can add a container element with overflow-x:auto around the table, and it will display a horizontal scroll bar when needed.</p>
    <p>Resize the browser window to see the effect. Try to remove the div element and see what happens to the table.</p>
    
    <div style="overflow-x:auto; width:100%;">
      <table>
        <tr>
          <th>First Name</th>
          <th>Last Name</th>
          <th>Points</th>
          <th>Points</th>
          <th>Points</th>
          <th>Points</th>
          <th>Points</th>
          <th>Points</th>
          <th>Points</th>
          <th>Points</th>
          <th>Points</th>
          <th>Points</th>
        </tr>
        <tr>
          <td>Jill</td>
          <td>Smith</td>
          <td>50</td>
          <td>50</td>
          <td>50</td>
          <td>50</td>
          <td>50</td>
          <td>50</td>
          <td>50</td>
          <td>50</td>
          <td>50</td>
          <td>50</td>
        </tr>
        <tr>
          <td>Eve</td>
          <td>Jackson</td>
          <td>94</td>
          <td>94</td>
          <td>94</td>
          <td>94</td>
          <td>94</td>
          <td>94</td>
          <td>94</td>
          <td>94</td>
          <td>94</td>
          <td>94</td>
        </tr>
        <tr>
          <td>Adam</td>
          <td>Johnson</td>
          <td>67</td>
          <td>67</td>
          <td>67</td>
          <td>67</td>
          <td>67</td>
          <td>67</td>
          <td>67</td>
          <td>67</td>
          <td>67</td>
          <td>67</td>
        </tr>
      </table>
    </div>
    
    </body>
    </html>