Tuesday, December 26, 2017

Flexbox type fixed header, scrollable content for table markup

Leave a Comment

I am using a data table for which i am using the traditional table markup but what i want is my table start from somewhere in the page and i want my table header to be fixed where it starts and table body should scroll by taking the remaining page height
i am showing a small example here

https://codepen.io/avreddy/pen/eyYBdB?editors=1100

.datatable{    width: 50%;    border-collapse: collapse;  }  td{    text-align: center;    border: 1px solid;    padding:5px;  }
<body>    <div class="somecontent">      <h4>Some Content</h4><h4>Some Content</h4><h4>Some Content</h4>    </div>    <table class="datatable">      <thead>        <tr>        <th>col1</th>        <th>col2</th>        <th>col3</th>        </tr>      </thead>      <tbody>        <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><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><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><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>  </body>


I know we can get it from flex-box responsive table but my limitation is i have to use traditional table markup so if tell me if there is any other way than flexbox responsive table
Thank you

4 Answers

Answers 1

Scrollable table + fixed header tricks cannot work with automatic column widths. This is because they change the display property of tbody element which creates a new (anonymous) table having different column widths.

The best solution I could think of is to create a copy of the table (so that both have identical content and therefore identical column widths) and manipulate them independently.

In the following example, I use jQuery to create a copy of table and visibility: collapse to hide the table header and body:

$(function() {    $("#button-1").one("click", function() {      $(".datatable").clone().insertAfter(".datatable");      $(".datatable").eq(0).addClass("tablehead");      $(".datatable").eq(1).addClass("tablebody");    });  });
/* full height */  html { height: 100%; }  body { height: 100%; margin: 0; padding: 0; font: medium monospace; }    /* make last item scrollable and occupy available height */  #wrapper { height: 100%; display: flex; flex-direction: column; overflow-y: hidden; }  #wrapper > :last-child { display: block; flex: 1; overflow-y: auto; }    /* make thead and tbody collapse when JavaScript adds the classes */  .datatable.tablehead tbody { visibility: collapse; }  .datatable.tablebody thead { visibility: collapse; }    /* beautify */  .datatable { border-collapse: collapse; }  .datatable th { border: 1px solid; background-color: #CCC; }  .datatable td { border: 1px solid; padding: 5px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>    <!--  Notes:    1) Using a wrapper div instead of body because third party scripts  often append elements to body element breaking our flex model    2) Width of second column is determined by thead > 1st row > 2nd column  while width of third column is determined by tbody > 1st row > 3rd column    3) If JavaScript fails the result is still usable  -->    <div id="wrapper">    <div>      <h4>Some Content</h4>      <h4>Some Content</h4>      <p><button type="button" id="button-1">Convert to fixed header</button></p>    </div>    <table class="datatable">      <thead>        <tr>          <th>col 1</th>          <th>col 2 (wide header)</th>          <th>col 3</th>        </tr>      </thead>      <tbody>        <tr>          <td>1</td>          <td>2</td>          <td>3 (wide content)</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>        <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>        <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>        <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>

Note that visibility: collapse is not implemented properly in all browsers. Alternate solution is to wrap the two tables inside divs: fixed height div for header table, scrollable div for body table. But then you need to set the height of the header.

Answers 2

.datatable{    width: 50%;    border-collapse: collapse;  }    /*this code is added to fix header at the top of the screen*/    thead th{    position: sticky; /*stick the element*/    top: 0px;    background: grey;  }  td{    text-align: center;    border: 1px solid;    padding:5px;  }
<body>    <div class="somecontent">      <h4>Some Content</h4><h4>Some Content</h4><h4>Some Content</h4>    </div>    <table class="datatable">      <thead>        <tr>        <th>col1</th>        <th>col2</th>        <th>col3</th>        </tr>      </thead>      <tbody>        <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><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><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><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>  </body>

you want something like this header will be sticky on top of the page.

Answers 3

Try position: sticky for your thead.

You need to apply it to the th to work in all browsers.

thead th {     position: sticky;           // Sticky makes it, well, sticky     top: 0px;                   // At which offset it should become sticky     background-color: #fff;     // Otherwise the th is transparent } 

Codepen


To make it sticky from it's current position, you can use a little javascript:

let topOffset = document.getElementById("datatable").offsetTop; let elementList = document.querySelectorAll('.datatable thead th');  for (i = 0; i < elementList.length; i++) {   elementList[i].style.top = topOffset + 'px'; } 

It may look a little weird now in the pen (overlap/transparency), but when you say there is content above the thead (a header, an alertbox, ..), just a apply a zIndex higher than the table, and it should look fine.

I'm currently working on a website with a fullscreen table, a sticky header, and a variable height content block above it, and this is what I use (although the offset is calculated a little different with AngularJS).

Codepen

Answers 4

I think it works.

<style>  table {     max-width:980px;     table-layout:fixed;  } th, td {     padding:5px 10px;     border:1px solid #000; } thead, tfoot {     background:#f9f9f9;     display:table;     width:100%;     width:calc(100% - 18px); } tbody {     height:300px;     overflow:auto;     overflow-x:hidden;     display:block;     width:100%; } tbody tr {     display:table;     width:100%;     table-layout:fixed; }  </style> 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment