Create a scrollable container for a table without fixed size that also prevents scroll bars on parent elements including browser window

Viewed 382

Desired output:

  • The red div (table-container) will display vertical / horizontal scroll bars around the table it contains.
  • No scroll bars will appear on the browser window or parent element.

Actual output:

  • Horizontal and vertical scroll bars are displayed on the browser window as well as the table-container div.

  • Height of the table is not constrained.

Solutions I would like to avoid:

  • Placing a fixed height/width on table-container. Note that body is constrained to 100vh/vw.

  • Attempting to modify the table i.e. using something like table-layout.

Edit: Table height and width are specified in this example html only to illustrate the problem. In my application I have no control over the size of the table and it is quite large.



    <html>
    <head>
    <style>

    body, html {
        height:100vh;
        width:100vw;
        max-height:100vh;
        max-width:100vw;
        display:flex;
        flex:1;
        margin:0;
        padding:0;
    }


    footer {
        display:flex;
        height: 10vh;
        min-height: 10vh;
        background-color:#666666;
    }

    .page 
    {
        display:flex;
        flex:1 1 auto;
        flex-direction:row;
    }

    .side-nav {
      display: flex;
      flex:0 1 auto;
      flex-flow: column;
      width:20vw;
      min-width:20vw;
      height:100vh;
      min-height:100vh;
      background-color:#99ccff;
    }

    .content {
      display: flex;
      flex-direction:column;
      flex:1 1 auto;
      background-color:#cccccc;
    }

    .col-layout {
        display:flex;
        flex:1 1 auto;
        flex-direction:column;
    }

    .table-container {
        display:flex;
        flex-direction:column;
        overflow-x:scroll;
        overflow-y:scroll;
        margin:3%;
        background-color:red;
        width:90%;
        max-width:90%;
        height:90%;
        max-height:90%;
    }



    table {
        margin:3%;
        width:1500px;
        height:2000px;
        background-color:#3399ff;
    }

    </style>
    </head>
    <body>
    <div class="page">
      <div class="side-nav">
        <label>Side Nav</label>
      </div>

      <div class="col-layout">
          <div class="content">
            <label>Content</label>
            <label>The red div should have vertical and horizontal scroll bars - no vertical or horizontal scroll bars should appear on the browser window.</label>
            <div class="table-container">
                <table>
                    <tr><td>key</td><td>value</td></tr>
                </table>
            </div>
          </div>
            
          <footer>
            <label>Footer</label>
          </footer>
      </div>
    </div>

    </body>
    </html>
2 Answers

Prevent the size of the table from affecting the size of its flex item ancestors by setting their min-width and min-height to something else than auto.

The reason you’re getting scrollbars on the browser window right now is that the ancestors of your table—.table-container, .col-layout—are flex items, and flex items derive their minimum size from their content by default. So if the content is a huge table (and it’s huge because it has lots of content, or because we explicitly set width and/or height), then the flex items up your element hierarchy will try to “protect” this size.

We can confirm this by looking at the Firefox DevTools layout inspector: enter image description here

This behavior can be changed by setting min-width or min-height. The initial value is auto, and that’s what leads to this content-derived sizing in Flexbox. So, for example, if you have a flex container with flex-direction: row, you’ll want to change min-width from auto to something else.

In our case, we want to completely ignore the size of our table. So we’ll set min-width and min-height to 0 for all elements where table could affect their size.

Here’s a working example:

body {
  margin: 0;
  height: 100vh;
  display: flex;
}

nav {
  padding: 32px;
  background-color: bisque;
}

section {
  flex: auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

main {
  flex: auto;
  min-height: 0;
  padding: 8px;
  display: flex;
  flex-direction: column;
}

h1 {
  font-size: 16px;
  font-weight: bold;
}

footer {
  padding: 24px;
  background-color: burlywood;
}

.table-container {
  flex: auto;
  min-height: 0;
  background-color: tomato;
  padding: 16px;
  overflow: auto;
}

table {
  width: 1500px;
  height: 2000px;
  background-color: steelblue;
  border: 10px solid white;
}
<body>
  <nav>Side nav</nav>
  <section>
    <main>
      <h1>Content with the table container</h1>
      <div class="table-container">
        <table>
          <thead>
            <tr>
              <th colspan="2">The table header</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>The table body</td>
              <td>with two columns</td>
            </tr>
          </tbody>
        </table>
      </div>
    </main>
    <footer>Footer</footer>
  </section>
</body>

The thing that you wanted to do is possible if you give height/width of .table-container in either vh units or hard code like px,cm,em .

  • But the way you want to do is not possible because if you give measurements in soft code then the container will adapt to the the width of of table and it will also effect to those whose width is not specified and renders to the width of table

body,
html {
  height: 100vh;
  width: 100vw;
  max-height: 100vh;
  max-width: 100vw;
  display: flex;
  flex: 1;
  margin: 0;
  padding: 0;
}

footer {
  display: flex;
  height: 10vh;
  min-height: 10vh;
  background-color: #666666;
}

.page {
  display: flex;
  flex: 1 1 auto;
  flex-direction: row;
}

.side-nav {
  display: flex;
  flex: 0 1 auto;
  flex-flow: column;
  width: 20vw;
  min-width: 20vw;
  height: 100vh;
  min-height: 100vh;
  background-color: #99ccff;
}

.content {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  background-color: #cccccc;
}

.col-layout {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
}

.table-container {
  display: flex;
  flex-direction: column;
  overflow-x: scroll;
  overflow-y: scroll;
  margin: 3%;
  background-color: red;
  width: 120vh;
  height: 60vh;
}

table {
  margin: 3%;
  width: 1500px;
  height: 2000px;
  background-color: #3399ff;
}
<html>

<head>

</head>

<body>
  <div class="page">
    <div class="side-nav">
      <label>Side Nav</label>
    </div>

    <div class="col-layout">
      <div class="content">
        <label>Content</label>
        <label>The red div should have vertical and horizontal scroll bars - no vertical or horizontal scroll bars should appear on the browser window.</label>

        <div class="table-container">
          <table>
            <tr>
              <td>key</td>
              <td>value</td>

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

      </div>

      <footer>
        <label>Footer</label>
      </footer>
    </div>
  </div>

</body>

</html>

See effect in full page

Related