nullException
nullException

Reputation: 1112

CSS 100% height layout with a scrollable table body

I have a 100% height layout split to three parts: header, content, footer.

I'd like to display a table inside a the content section with 100% height and i want the table body to have a vertical scroll bar for the table body content.

How can i do that?

it seems like i cannot set the tbody height to 100% and have a scrollbar?

html, body {
     height: 100%;
     padding: 0;
     margin: 0;
}
 #container {
     display: table;
     width: 100%;
     height: 100%;
     border: 1px solid red;
     text-align: center;
}
 #container > div {
     display: table-row;
     width: 100%;
}
 #container > div > div {
     display: table-cell;
     width: 100%;
     border-radius:10px;
}
 #header > div {
     height:50px;
     border:solid 2px #aaa;
}
 #content > div {
     height: 100%;
     background:#f0f4f0;
     border:solid 2px #5a5;
}
 #footer > div {
     height:50px;
     border:solid 2px #a55;
}
 table {
     table-layout:fixed;
     margin:auto;
}
 th, td {
     padding:5px 10px;
     border:1px solid #000;
}
 thead, tfoot {
     background:#f9f9f9;
     display:table;
     width:100%;
     width:calc(100% - 18px);
}
 tbody {
     height:400px;
     overflow:auto;
     overflow-x:hidden;
     display:block;
     width:100%;
}
 tbody tr {
     display:table;
     width:100%;
     table-layout:fixed;
}
 
<div id="container">
    <div id="header">
        <div>header</div>
    </div>
    <div id="content">
        <div>
            <table>
                <thead>
                    <tr>
                        <th scope="col">Header 1</th>
                        <th scope="col">Header 2</th>
                        <th scope="col">Header 3</th>
                        <th scope="col">Header 4</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>Cell2 content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                    <tr>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                        <td>Cell content</td>
                    </tr>
                </tbody>
                <tfoot>
                    <tr>
                        <td>Footer 1</td>
                        <td>Footer 2</td>
                        <td>Footer 3</td>
                        <td>Footer 4</td>
                    </tr>
                </tfoot>
            </table>
        </div>
    </div>
    <div id="footer">
        <div>footer</div>
    </div>
</div>

Upvotes: 3

Views: 2638

Answers (2)

Danny
Danny

Reputation: 1113

I had to use javascript for this but maybe someone can come up with a pure CSS solution.

Main sections of the page

I'm using flexbox to position the header, main and footer sections of the page allowing the main to take up as much vertical space that it can:

body {
  display: flex;
  flex-direction: column;
}

main {
  flex: 1;
}

The Table

I set the table to take up 100% of the height and width in the main section and set each tr element to display flex allowing all their direct child elements to take up equal amounts of space:

table {
  width: 100%;
  height: 100%;
}

tr {
  display: flex;
}
tr > * {
  flex: 1;
}

I've set the tbody element to display: block which will allow for content to be scrollable if it overflows:

tbody {
  display: block;
  overflow-y: scroll;
}
tbody tr {
  height: 40vh; // for demonstrating the scrolling of the tbody
}

I then used some javascript to set the height of the tbody element, please find the documentation in the comments below:

setTbodyHeight();
window.addEventListener("resize", setTbodyHeight);

function setTbodyHeight() {
  // get the viewport height
  let viewportHeight = window.innerHeight;

  // calculate how much of the height the main should consume
  let headerHeight = getHeight("header");
  let footerHeight = getHeight("footer");

  let mainHeight = viewportHeight - (headerHeight + footerHeight);

  // from the main height calcuate how much space would be available if you subtracted the tfoot/thead height
  let theadHeight = getHeight("thead");
  let tfootHeight = getHeight("tfoot");

  let tbodyHeight = mainHeight - (theadHeight + tfootHeight);

  // set the height of the tbody to this value
  let tbody = document.querySelector("tbody");
  tbody.style.height = tbodyHeight + "px";

  function getHeight(elementName) {
    let element = document.querySelector(elementName);
    let elementCSS = window.getComputedStyle(element);

    let height = parseInt(elementCSS.getPropertyValue("height"));

    return height;
  }
}
/* IGNORE RULES FROM HERE.....*/

html,
body {
  height: 100%;
}

body {
  font-family: sans-serif;
  margin: 0;
}

header::after,
footer::after {
  content: "." attr(class);
}

tbody tr:nth-child(even) {
  background: firebrick;
  color: white
}

td {
  text-align: center;
}


/*.....TO HERE*/

body {
  display: flex;
  flex-direction: column;
}

main {
  flex: 1;
}

table {
  width: 100%;
  height: 100%;
}

tr {
  display: flex;
}

tr>* {
  flex: 1;
}

tbody {
  display: block;
  overflow-y: scroll;
}

tbody tr {
  height: 20vh;
}

tbody td {
  line-height: 20vh;
}
<header class="header"></header>
<main class="main">
  <table>
    <thead>
      <tr>
        <th>Heading</th>
        <th>Heading</th>
        <th>Heading</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
      </tr>
      <tr>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
      </tr>
      <tr>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
      </tr>
      <tr>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
      </tr>
      <tr>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
      </tr>
      <tr>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
      </tr>
    </tbody>
    <tfoot>
      <tr>
        <td>Footer</td>
        <td>Footer</td>
        <td>Footer</td>
      </tr>
    </tfoot>
  </table>
</main>
<footer class="footer"></footer>

Upvotes: 1

Itay Gal
Itay Gal

Reputation: 10824

Your layout is a bit messed up. Too many containing div in my opinion. Did some changes using flex - so the table container will have

display: flex;
flex-direction: column;
overflow: auto;

and the table will have flex-grow: 1;

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

#container {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  border: 1px solid red;
  text-align: center;
}

#container>div {
  width: 100%;
  display: flex;
  flex-direction: column;
}

#container>div>div {
  width: 100%;
  height: 100%;
  border-radius: 10px;
  overflow: auto;
}

#header {
  flex-basis: 50px;
  flex-grow: 0;
  flex-shrink: 0;
}

#header>div {
  height: 50px;
  border: solid 2px #aaa;
}

#content {
  flex-grow: 1;
}

#content>div {
  height: 100%;
  background: #f0f4f0;
  border: solid 2px #5a5;
  display: flex;
  flex-direction: column;
}

#footer{
  flex-basis: 50px;
  flex-grow: 0;
  flex-shrink: 0;
}

#footer>div {
  height: 50px;
  border: solid 2px #a55;
}

table {
  flex-grow: 1;
  table-layout: fixed;
  margin: auto;
}

th,
td {
  padding: 5px 10px;
  border: 1px solid #000;
}

thead,
tfoot {
  background: #f9f9f9;
  display: table;
  width: 100%;
  width: calc(100% - 18px);
}

tbody {
  overflow: auto;
  overflow-x: hidden;
  display: block;
  width: 100%;
}

tbody tr {
  display: table;
  width: 100%;
  table-layout: fixed;
}
<div id="container">
  <div id="header">
    <div>header</div>
  </div>
  <div id="content">
    <div>
      <table>
        <thead>
          <tr>
            <th scope="col">Header 1</th>
            <th scope="col">Header 2</th>
            <th scope="col">Header 3</th>
            <th scope="col">Header 4</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>Cell2 content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
          <tr>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
            <td>Cell content</td>
          </tr>
        </tbody>
        <tfoot>
          <tr>
            <td>Footer 1</td>
            <td>Footer 2</td>
            <td>Footer 3</td>
            <td>Footer 4</td>
          </tr>
        </tfoot>
      </table>
    </div>
  </div>
  <div id="footer">
    <div>footer</div>
  </div>
</div>

Upvotes: 1

Related Questions