4

The table below contains a sticky table header, however I would like a few of the table header cells to be rotated. The issue here is that currently these table header cells (<th> elements) will be appearing outside of the screen or table header itself (<thead> element).

Is it possible to make a sticky table header with rotated header cells?

Working table with sticky header (optional sample code):

.example {
  padding: 5px;
  margin: 5px 0;
  border-radius: 2px;
  background-color: #afc8f0;
  text-align: center;
}

.sticky-table thead tr th {
  position: sticky;
  top: -1px;
  background-color: #fff;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div class="container">
  <div class="row">
    <div class="col">

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <!-- ...
        Some other elements
        .. -->

      <table class="table table-striped table-hover table-sm sticky-table">
        <thead>
          <tr>
            <th scope="col">#</th>
            <th scope="col">First</th>
            <th scope="col">Last</th>
            <th scope="col">Handle</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
        </tbody>
      </table>

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <!-- ...
        Some other elements
        .. -->

    </div>
  </div>
</div>

JSFiddle

Broken table with sticky header (this piece of code contains what I am trying to do):

Added style="transform: rotate(-90deg); text-align: center;" to a <th> element.

.example {
  padding: 5px;
  margin: 5px 0;
  border-radius: 2px;
  background-color: #afc8f0;
  text-align: center;
}

.sticky-table thead tr th {
  position: sticky;
  top: -1px;
  background-color: #fff;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div class="container">
  <div class="row">
    <div class="col">

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <!-- ...
        Some other elements
        .. -->

      <table class="table table-striped table-hover table-sm sticky-table">
        <thead>
          <tr>
            <th scope="col">#</th>
            <th scope="col" style="transform: rotate(-90deg); text-align: center;">First</th>
            <th scope="col">Last</th>
            <th scope="col">Handle</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
        </tbody>
      </table>

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <!-- ...
        Some other elements
        .. -->

    </div>
  </div>
</div>

JSFiddle

(To replicate the problem, please try to scroll down and see the result. The table header will not be entirely visible and when assigning a background-color to all the <th> elements, it will appear outside of the <thead> as well).

The reason for the rotation is because I want to save some space in width of the table by changing table header orientation.

Am I required to rather write some JavaScript for this kind of behaviour or will plain CSS be able to solve this issue too?

Barrosy
  • 1,407
  • 2
  • 25
  • 56

1 Answers1

1

You could instead of rotating the text as a block, have the text written in a top-to-bottom instead of left-to-right orientation:

(Thanks to Константин Ван for the inspiration)

.example {
  padding: 5px;
  margin: 5px 0;
  border-radius: 2px;
  background-color: #afc8f0;
  text-align: center;
}

.sticky-table thead tr th {
  position: sticky;
  top: -1px;
  background-color: #fff;
}

.sticky-table thead tr th.vertical {
  -webkit-text-orientation: upright;
  -webkit-writing-mode: vertical-rl;
  text-orientation: upright;
  writing-mode: vertical-rl;
  text-align: center;
}

.sticky-table thead tr th.vertical span.chromeFix
{
  text-orientation: upright;
  writing-mode: vertical-rl;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div class="container">
  <div class="row">
    <div class="col">

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <!-- ...
        Some other elements
        .. -->

      <table class="table table-striped table-hover table-sm sticky-table">
        <thead>
          <tr>
            <th scope="col">#</th>
            <th scope="col" class="vertical"><span class="chromeFix">First</span></th>
            <th scope="col">Last</th>
            <th scope="col">Handle</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
          <tr>
            <th scope="row">1</th>
            <td>Mark</td>
            <td>Otto</td>
            <td>@mdo</td>
          </tr>
          <tr>
            <th scope="row">2</th>
            <td>Jacob</td>
            <td>Thornton</td>
            <td>@fat</td>
          </tr>
          <tr>
            <th scope="row">3</th>
            <td>Larry</td>
            <td>the Bird</td>
            <td>@twitter</td>
          </tr>
        </tbody>
      </table>

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <div class="example">
        ... Sample content ...
      </div>

      <!-- ...
        Some other elements
        .. -->

    </div>
  </div>
</div>

Notes

Having checked in Edge, this might not be the best solution, as it's not compatible with all browsers.

Thanks to Turnip for pointing out that this only works in Chrome if you wrap the text in a span or some such thing.

Community
  • 1
  • 1
Matt Ellen
  • 11,268
  • 4
  • 68
  • 90
  • Am I missing something? All this does is center `First`. – Patrick Roberts Jul 04 '19 at 10:40
  • This makes "first" be displayed with the letters underneath eachother. I can't show you in a comment, but it's distinct to the OP's "broken" version. – Matt Ellen Jul 04 '19 at 10:51
  • @PatrickRoberts this works in Firefox, other browsers seem to have difficulty. – Matt Ellen Jul 04 '19 at 10:57
  • This doesn't work in the latest version of Chrome unless the text is wrapped in another element (``, `

    ` etc.)

    – Turnip Jul 04 '19 at 10:57
  • Yeah I might need something that is more compatible. – Barrosy Jul 04 '19 at 11:04
  • @Turnip weirdly mdn's [page on writing-mode](https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode) lists chrome as supporting it with a prefix, but I can't get it to work. – Matt Ellen Jul 04 '19 at 11:09
  • If you wrap the word "First" in a `div` and apply the styles to the `div` rather than the `th` it works. @MattEllen - Example: https://jsfiddle.net/80fz6rem/ – Turnip Jul 04 '19 at 11:37
  • This kind of looks like something I could use, though I am still curious if there would be a possible solution for just plain rotation as well. – Barrosy Jul 04 '19 at 12:06