0

I have a simple 3-part layout (header/sidebar/content) using css grid. Inside my content, I have a table.

I want the table to fill the remaining space in the div.content and have a tbody with its own scrollbar.

Every combination of overflow-y: scroll; and position: relative with various widths/heights results in either the div.content getting the scrollbar, or the <table> overflowing (see example - also on jsbin).

How can I make this tables <tbody> receive the scrollbar, and have the table itself bounded by the content div without overflowing?

html, body {
  margin: 0;
  height: 100%;
}

main {
  display: grid;
  grid-template-areas: 'header header' 'sidebar content';
  grid-template-rows: 100px 1fr;
  grid-template-columns: 200px 1fr;
  width: 100%;
  height: 100%;
}


header {
  background-color: #CCC;
  grid-area: header;
  padding: 20px;
}
aside {
  background-color: #EEE;
  grid-area: sidebar;
  padding: 10px;
}
aside img {
  width: 100%;
  mix-blend-mode: darken;
}
div.content {
  position: relative;
  display: flex;
  flex-direction: column;
  grid-area: content;
  min-height: 0;
  min-width: 0;
  padding: 10px;
  max-height: 100%;
  border-bottom: 2px solid black;
  overflow-y: scroll;
}

table {
  margin: 10px;
  width: 100%;
}
thead {
  text-align: left;
}
tbody {
  height: 100%;
  overflow-y: scroll;
}

.code {
  font: 12px Courier;
  color: blue;
}
<main>
      <header>
        <h2>Really rad app title</h2>
      </header>
      <aside>
        <img src="https://thumb7.shutterstock.com/display_pic_with_logo/436114/423846025/stock-vector-example-stamp-423846025.jpg" />
        <span>Some Contextual Informations and other such sidebar-y things<span>
      </aside>
      <div class="content">
        <h3>Some Stuffs</h3>
        <div>
          Why does this <span class="code">&lt;tbody&gt;</span> ignore my <span class="code">overflow-y: scroll;</span>?
          <br /><br />
          I want <span class="code">div.content</span> to act as a portal/window, with everything around it remaining fixed; but I want the table to stop before the bottom of this window and have a scrollable body (instead of scrolling this text offscreen).
        </div>
      
        <table>
          <thead><tr><th>One</th><th>Two</th><th>Three</th></tr></thead>
          <tbody>
<tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
          <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
          <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
          <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
          <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
          <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
          <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
          <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
          <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
          </tbody>
        </table>
      </div>
    </main>
Alex McMillan
  • 17,096
  • 12
  • 55
  • 88

2 Answers2

2

Seems like tables have no concept of height, so us a wrapping div and add a flex-grow to it instead (you're using flexbox already).

Main changes:

wrapped table with <div class='fill'></div>

css addition div.content .fill { flex: 1; overflow-y: scroll }

related: CSS3 display:table, overflow-y:scroll doesn't work

html, body {
  margin: 0;
  height: 100%;
}

main {
  display: grid;
  grid-template-areas: 'header header' 'sidebar content';
  grid-template-rows: 100px 1fr;
  grid-template-columns: 200px 1fr;
  width: 100%;
  height: 100%;
}


header {
  background-color: #CCC;
  grid-area: header;
  padding: 20px;
}
aside {
  background-color: #EEE;
  grid-area: sidebar;
  padding: 10px;
}
aside img {
  width: 100%;
  mix-blend-mode: darken;
}
div.content {
  position: relative;
  display: flex;
  flex-direction: column;
  grid-area: content;
  min-height: 0;
  min-width: 0;
  padding: 10px;
  max-height: 100%;
  border-bottom: 2px solid black;
  overflow-y: scroll;
}

div.content .fill {
  flex: 1;
  overflow-y: scroll;
}

table {
  width: 100%;
  height: 100px;
  overflow: auto;
}
thead {
  text-align: left;
}
tbody {
  height: 100%;
  overflow-y: scroll;
}

.code {
  font: 12px Courier;
  color: blue;
}
<main>
      <header>
        <h2>Really rad app title</h2>
      </header>
      <aside>
        <img src="https://thumb7.shutterstock.com/display_pic_with_logo/436114/423846025/stock-vector-example-stamp-423846025.jpg" />
        <span>Some Contextual Informations and other such sidebar-y things<span>
      </aside>
      <div class="content">
        <h3>Some Stuffs</h3>
        <div>
          Why does this <span class="code">&lt;tbody&gt;</span> ignore my <span class="code">overflow-y: scroll;</span>?
          <br /><br />
          I want <span class="code">div.content</span> to act as a portal/window, with everything around it remaining fixed; but I want the table to stop before the bottom of this window and have a scrollable body (instead of scrolling this text offscreen).
        </div>
        <div class='fill'>
            <table>
              <thead><tr><th>One</th><th>Two</th><th>Three</th></tr></thead>
              <tbody>
    <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Some content</td><td>Some Content</td><td>Some Content</td></tr>
              <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
              <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
              <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
              <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
              <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
              <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
              <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
              <tr><td>Too much content</td><td>Too much content</td><td>Too much content</td></tr>
              </tbody>
            </table>
        </div>
      </div>
    </main>
A. L
  • 11,695
  • 23
  • 85
  • 163
  • Brilliant! Thank you. However, I wanted the `` to scroll (ie: keep the headers static), so I made it `overflow-y: hidden;` and let the `overflow-y: scroll;` on the tbody take over. But thanks for the wrapper idea... man HTML/CSS can be unintuitive sometimes. – Alex McMillan Sep 12 '17 at 00:07
  • @AlexMcMillan yeah css/html just doesn't behave as you would like/expect them to. You also cannot have a fixed header with the deafult `` (as much as I would love to have that as well) it will require some gimmicky manipulation (mostly javascript to make sure their widths are the same).
    – A. L Sep 12 '17 at 00:13
  • If you're just using three columns, maybe use columns instead? You could probably manipulate a fixed header with scrollable body more easily that way. https://www.w3schools.com/css/css3_multiple_columns.asp – A. L Sep 12 '17 at 00:14
  • My real-world table is a React component with variable columns; thanks for the link, I will look into that. – Alex McMillan Sep 12 '17 at 00:19
  • If the is itself wrapped in a custom element (think Angular), then there is a disconnect between the table sizing and the content div. Is there a solution for this?
    – MJZ Apr 22 '22 at 21:46
0

You have to give another value of height of the tbody like

tbody {
height: 200px;
overflow-y: scroll;
}

and also to display thead, tbody, tr and td display them with blok property: .table-fixed thead, .table-fixed tbody, .table-fixed tr, .table-fixed td, .table-fixed th { display: block; }

Use Bootstrap that alow you to make a simple and effective page it's easy to work with:

here is an complete ex that works for me :

this is the html file:

<html>
<head>
 <meta charset="utf-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width, initial-scale=1">

 <!-- Bootstrap -->
 <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
 <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
 <!--style -->
 <link rel="stylesheet" type="text/css" href="style/monStyle">
 <!-- Scripts-->
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>  
<!--Table of list of employers-->
<div class="container">
  <table class="table table-fixed table-bordered">
    <thead>
      <tr>
        <th class="col-xs-2">N° </th>
        <th class="col-xs-3">Date </th>
        <th class="col-xs-2">Nombre J </th>
        <th class="col-xs-3">Intr</th>
        <th class="col-xs-2">Avis</th>
      </tr>
    </thead>
    <tbody>
     <tr>
      <td class="col-xs-2">1</td>
      <td class="col-xs-3">12/12/2016</td>
      <td class="col-xs-2">5 </td>
      <td class="col-xs-3">Dina</td>
      <td class="col-xs-2">Accepté</td>
    </tr>
    <tr>
      <td class="col-xs-2">2</td>
      <td class="col-xs-3">12/12/2016</td>
      <td class="col-xs-2">5 </td>
      <td class="col-xs-3">Lili</td>
      <td class="col-xs-2">Refusé</td>
    </tr>
  </tbody>
</table>
</div>
</body>
</html>

and this is the css file :

 body {
    background-color: #bdc3c7;
    width: 800px;
    }
 /**Liste of emp**/
 .table-fixed {
 width: 100%;
 background-color: #f3f3f3;
 margin-top:10px;
 }
 .table-fixed tbody {
 max-height: 500px;
 height: 200px;
 overflow-y: auto;
 overflow-x: auto;
 width: 100%;
 }
 .table-fixed thead, .table-fixed tbody, .table-fixed tr, .table-fixed td, .table-fixed th {
 display: block;
 }
 .table-fixed tbody td {
 float: left;
 }
 .table-fixed thead tr th {
 color: white;
 float: left;
 background-color:#42b43b ;

 }
 /* Buttom to diplay the information of empl*/
 .btncosulter
 {
 color:black;
 background-color:#f3f3f3;
 width:80px;
 border:none;
 height: 20px;
 }
 .btndec
 {
 color:black;
 background-color:#f3f3f3;
 width:35px;
 border:none;
 height: 20px;
 }
 h3
 {
 margin-left:16px;
 }
 #lstEmp
 {
 margin-top:-43px;
 }
Zina Taklit
  • 89
  • 2
  • 11