Passion & Opportunity ? continue : break

How to make a rotatable table?
Written: 2019-03-06 16:20:02 Last update: 2019-06-16 11:19:48

These days, Responsive Web Design (RWD) is playing important role for webmasters, we used to read the word 'responsive web' then we alread read many times about 'mobile first' design and then recently we read a few times about 'mobile only' design, it is confusing about those 3 designs because people have different needs based on their visitors/customers. No matter which design we choose, the ability to adjust our web layout and content for various screen sizes is very important.

One of the most troublesome to handle 'layout' for tabular data content is the <table> tag, there are some ways to make 'responsive table' (ie: ability to joined some columns as one to reduce width), there are some articles out there to described the ways and each pros/cons.

This short article will only show how to create 'rotatable table', it can change the header's orientation between landscape and portait depending on viewport (viewing area) width. To avoid misunderstanding regarding 'rotatable table' definition, below is the definition that I use for this short article

  • Only use native <table>, <thead>, <tr>, <th>, <td> tags (don't use any <div> or <span> tags to define cell areas).
  • Header area will be always visible (sticky) even when the content is scrolled very far.
  • Header location may be rotated between 'landscape' (horizontal) and 'portrait' (vertical) depending on viewport width, if viewport width is enough then header will be positioned on the top horizontally and content may scroll up and down, but if viewport width is not enough then header will be positioned on the left vertically and the content may scroll left and right.


DEMO NOTE:
  • To see the table header changing between top side (landscape) and left side (portrait), we need to adjust the width of our browser with mouse OR change our tablet's orientation from portrait to landscape and vice versa.
  • To show table header always visible (sticky) in this demo, I on purposely set smaller limit of the table width and height, so then we can scroll the content but still see the header columns are always visible.

Player Sport Score
Date Player name Sport name Total play Total score
2019-03-01 George Swimming 2 8
2019-03-01 Mike Boxing 6 18
2019-03-03 Josh Running 1 20
2019-03-05 Brandon Bicycling 4 24
2019-03-04 Harry Shooting 7 23
2019-03-05 Sandy Wrestling 3 7
2019-03-06 Jude Wrestling 4 11



The HTML

<table class="table-sticky-header">
<thead>
    <tr>
      <th>Date</th>
      <th>Player name</th>
      <th>Sport name</th>
      <th>Total play</th>
      <th>Total score</th>
    </tr>
</thead>

<tbody>
    <tr>
      <td>2019-03-01</td>
      <td>George</td>
      <td>Swimming</td>
      <td>2</td>
      <td>8</td>
    </tr>
    <tr>
      <td>2019-03-01</td>
      <td>Mike</td>
      <td>Boxing</td>
      <td>6</td>
      <td>18</td>
    </tr>
    <tr>
      <td>2019-03-03</td>
      <td>Josh</td>
      <td>Running</td>
      <td>1</td>
      <td>20</td>
    </tr>
    <tr>
      <td>2019-03-05</td>
      <td>Brandon</td>
      <td>Bicycling</td>
      <td>4</td>
      <td>24</td>
    </tr>
    <tr>
      <td>2019-03-04</td>
      <td>Harry</td>
      <td>Shooting</td>
      <td>7</td>
      <td>23</td>
    </tr>
    <tr>
      <td>2019-03-05</td>
      <td>Sandy</td>
      <td>Wrestling</td>
      <td>3</td>
      <td>7</td>
    </tr>
    <tr>
      <td>2019-03-06</td>
      <td>Jude</td>
      <td>Wrestling</td>
      <td>4</td>
      <td>11</td>
    </tr>
</tbody>
</table>



The CSS style

/* use CSS variable for EDGE > 15, absolute not for IE, if want to support more browser then do not use var() */
:root {
  --responsive-table-cell-height: 40px;
  --responsive-table-cell-width: 150px;
}

table.table-sticky-header {
  /* reset table properties */
  width: auto;
  display: unset;
}

/* each cell width and height */
.table-sticky-header th,
.table-sticky-header td {
  color: #fff;
  background-color: #000;
  border: 1px solid #ccc;

  /* header on top, so important to set same width for cell, all columns width will be the same */
  width: var(--responsive-table-cell-width);

  vertical-align: middle;
}

/* after set style for all cells above then define table header cell style again here */
.table-sticky-header th {
  background-color: #555;
}

.table-sticky-header thead {
  counter-reset: totalheader; 
}
.table-sticky-header th {
  counter-increment: totalheader; 
}

/* (optional) for DEMO purpose, we set limit width and height to be small so we can see the scrolling effect and see the 'sticky' (always visible) header */  
.table-sticky-header tbody {
  
  /* to set height, we need to use display block */
  display: block;

  /* limit height to see vertical scroller */
  height: 150px;

  /* because display: block, so we need to set width */
  /* total header (column) 5 * each cell width (150px) = 750px + 20px vertical scrollbar */
  width: calc((counter(totalheader) * var(--responsive-table-cell-width)) + 0px);

  overflow: auto;
}

/**
 if viewport width is not enough then we put the header on the left side
 total column = 5 * each cell width (150px) = 750px + 50px (for scrollbar + margin/padding) 
 20190307: media query using calc() is not working in Chrome/Firefox, so use hardcoded value 
 @media screen and (max-width: calc((counter(totalheader) * var(--responsive-table-cell-width)) + 50px)) { 
*/
@media screen and (max-width: 800px) {

  /* here we make the header positioned on the left-side */

  table.table-sticky-header {
    display: flex;
  }

  .table-sticky-header tbody {
    display: flex;

    /* show horizontal scroller */
    overflow-x: auto;

    /* hide vertical scroller */
    overflow-y: hidden; 

    /* important to set height
       total column = 5 * each cell height (40px) = 200px + (horizontal scrollbar's height)
       */
    height: calc((counter(totalheader) * var(--responsive-table-cell-height)) + 0px);
  }

  .table-sticky-header th,
  .table-sticky-header td {    
    /* header on left-side, so important to set same height for all cells */
    display: block;
    height: var(--responsive-table-cell-height);
  }
}

Summary

  • This is only one way to make table rotate between landscape and portrait mode, there are some other ways.
  • To position header to the left-side, we use 'display: flex' to make it easy.
  • This is the easiest way to implement 'rotatable table', simply using a single class attribute 'table-sticky-header' then we can create multiple tables to be rotatable.

Hardcoding issues:

  • Width (--responsive-table-cell-height: 40px;), we may need to adjust it for different table.
  • Height (--responsive-table-cell-width: 150px;)
  • '@media screen' could not use CSS calc(), please see the style above.

Is there a way to avoid hardcoding ? happy rotating tables...