96

Suppose i have table with some rows and column,so i want to rotate text in cells something like this
: enter image description here

problem is when i rotate text using style :

#rotate {
     -moz-transform: rotate(-90.0deg);  /* FF3.5+ */
       -o-transform: rotate(-90.0deg);  /* Opera 10.5 */
  -webkit-transform: rotate(-90.0deg);  /* Saf3.1+, Chrome */
             filter:  progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083);  /* IE6,IE7 */
         -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)"; /* IE8 */

it all get messed up like this

html code:

<table cellpadding="0" cellspacing="0" align="center">
    <tr>
        <td id='rotate'>10kg</td>
        <td >B</td>
        <td >C</td>
        <td>D</td>
        <td>E</td>
    </tr>
    <tr>
        <td id='rotate'>20kg</td>
        <td>G</td>
        <td>H</td>
        <td>I</td>
        <td>J</td>
    </tr>
    <tr>
        <td id='rotate'>30kg</td>
        <td>L</td>
        <td>M</td>
        <td>N</td>
        <td>O</td>
    </tr>


</table>

css:

<style type="text/css">
td {
    border-collapse:collapse;
    border: 1px black solid;
}
tr:nth-of-type(5) td:nth-of-type(1) {
    visibility: hidden;
}
#rotate {
     -moz-transform: rotate(-90.0deg);  /* FF3.5+ */
       -o-transform: rotate(-90.0deg);  /* Opera 10.5 */
  -webkit-transform: rotate(-90.0deg);  /* Saf3.1+, Chrome */
             filter:  progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083);  /* IE6,IE7 */
         -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)"; /* IE8 */
}
</style>
Kara
  • 6,115
  • 16
  • 50
  • 57
lata
  • 1,575
  • 3
  • 13
  • 21
  • @Mr_Green: transform: rotate(-90.0deg);i have added it in my code but no change. May i know what it is used for? – lata Apr 04 '13 at 09:12
  • possible duplicate of [Creating HTML table with vertically oriented text as table header](http://stackoverflow.com/questions/9434839/creating-html-table-with-vertically-oriented-text-as-table-header) – Don Kirkby Apr 28 '14 at 22:32

4 Answers4

98

Without calculating height. Strict CSS and HTML. <span/> only for Chrome, because the chrome isn't able change text direction for <th/>.

th 
{
  vertical-align: bottom;
  text-align: center;
}

th span 
{
  -ms-writing-mode: tb-rl;
  -webkit-writing-mode: vertical-rl;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
}
<table>
  <tr>
    <th><span>Rotated text by 90 deg.</span></th>
  </tr>
</table>
18C
  • 2,014
  • 10
  • 16
  • 6
    This is extremely cunning and very robust. Great idea, ought to be the accepted answer - no JS, no special width, height, margin etc. hacks - really nice. – Andrew Hodgkinson May 22 '18 at 22:45
  • To better effect, you can use additionally `th span{display:table; border-spacin:0; margin-left:...}` to avoid display differences between IE11, Firefox and Chrome. – 18C Jul 05 '18 at 12:38
  • exactly what i'm looking for, it automatically adjusts the height of the table header based on the content without any extra JavaScript! worked well with my use case. – stevenferrer Nov 06 '18 at 08:21
  • 5
    Looks like `sideways-lr` won't require the rotate 180deg hack, but only *Firefox* supports it right now. – mpen Oct 14 '19 at 01:46
  • 1
    For correct printing you need to use span. – Alex78191 Oct 05 '21 at 15:37
63

You can do that by applying your rotate CSS to an inner element and then adjusting the height of the element to match its width since the element was rotated to fit it into the <td>.

Also make sure you change your id #rotate to a class since you have multiple.

A 4x3 table with the headers in the first column rotated by 90 degrees

$(document).ready(function() {
  $('.rotate').css('height', $('.rotate').width());
});
td {
  border-collapse: collapse;
  border: 1px black solid;
}
tr:nth-of-type(5) td:nth-of-type(1) {
  visibility: hidden;
}
.rotate {
  /* FF3.5+ */
  -moz-transform: rotate(-90.0deg);
  /* Opera 10.5 */
  -o-transform: rotate(-90.0deg);
  /* Saf3.1+, Chrome */
  -webkit-transform: rotate(-90.0deg);
  /* IE6,IE7 */
  filter: progid: DXImageTransform.Microsoft.BasicImage(rotation=0.083);
  /* IE8 */
  -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)";
  /* Standard */
  transform: rotate(-90.0deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table cellpadding="0" cellspacing="0" align="center">
  <tr>
    <td>
      <div class='rotate'>10kg</div>
    </td>
    <td>B</td>
    <td>C</td>
    <td>D</td>
    <td>E</td>
  </tr>
  <tr>
    <td>
      <div class='rotate'>20kg</div>
    </td>
    <td>G</td>
    <td>H</td>
    <td>I</td>
    <td>J</td>
  </tr>
  <tr>
    <td>
      <div class='rotate'>30kg</div>
    </td>
    <td>L</td>
    <td>M</td>
    <td>N</td>
    <td>O</td>
  </tr>


</table>

JavaScript

The equivalent to the above in pure JavaScript is as follows:

jsFiddle

window.addEventListener('load', function () {
    var rotates = document.getElementsByClassName('rotate');
    for (var i = 0; i < rotates.length; i++) {
        rotates[i].style.height = rotates[i].offsetWidth + 'px';
    }
});
Daniel Imms
  • 47,944
  • 19
  • 150
  • 166
  • Note that the values 0.083 are for 7.5 degrees, and for IE10 you will need -ms-transform: rotate(-90.0deg); – David Sykes Apr 01 '14 at 12:18
  • 14
    This works for short text, but when entering longer text, the `td` will grow in width and there's no way to shrink it :( +1 though for the working case – Eduard Luca Jul 24 '14 at 08:25
  • @EduardLuca `max-width` helps, e.g. `max-width: 1em`, tested on Chrome—but cell-width is just one of the issues longer text introduces. At least (1) word-breaking and (2) positioning/alignment comes to mind. (1) can be helped with non-breaking characters and (2) with relative positioning instead of text-align esp. if the table/cell is somewhat static. Rotating is nevertheless far from ideal but can be useful in limited cases. – Jari Keinänen Sep 07 '15 at 13:18
  • 7
    Now try to make the column larger, and center the text - and booom - the layout explodes in your face ! Even in 2015, you still have to do this by writing a generic image handler for vertical text... That's just absurd. This shouldn't be that hard. It shoult be as easy aslalala, which it isn't, for whatever stupid reason. – Stefan Steiger Nov 12 '15 at 11:45
  • 1
    1st cell is square. not what you want. – Boris Gafurov Feb 19 '20 at 19:27
  • @EduardLuca to keep the TD from growing you need to a) set the TD as position:relative, b) set the inner container to position absolute. it'll be taken out of the flow for calculating the TD width – FirefighterBlu3 Oct 21 '21 at 19:12
53

Daniel Imms answer is excellent in regards to applying your CSS rotation to an inner element. However, it is possible to accomplish the end goal in a way that does not require JavaScript and works with longer strings of text.

Typically the whole reason to have vertical text in the first table column is to fit a long line of text in a short horizontal space and to go alongside tall rows of content (as in your example) or multiple rows of content (which I'll use in this example).

enter image description here

By using the ".rotate" class on the parent TD tag, we can not only rotate the inner DIV, but we can also set a few CSS properties on the parent TD tag that will force all of the text to stay on one line and keep the width to 1.5em. Then we can use some negative margins on the inner DIV to make sure that it centers nicely.

td {
    border: 1px black solid;
    padding: 5px;
}
.rotate {
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  width: 1.5em;
}
.rotate div {
     -moz-transform: rotate(-90.0deg);  /* FF3.5+ */
       -o-transform: rotate(-90.0deg);  /* Opera 10.5 */
  -webkit-transform: rotate(-90.0deg);  /* Saf3.1+, Chrome */
             filter:  progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083);  /* IE6,IE7 */
         -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)"; /* IE8 */
         margin-left: -10em;
         margin-right: -10em;
}
<table cellpadding="0" cellspacing="0" align="center">
    <tr>
        <td class='rotate' rowspan="4"><div>10 kilograms</div></td>
        <td>B</td>
        <td>C</td>
        <td>D</td>
        <td>E</td>
    </tr>
    <tr>
        <td>G</td>
        <td>H</td>
        <td>I</td>
        <td>J</td>
    </tr>
    <tr>
        <td>L</td>
        <td>M</td>
        <td>N</td>
        <td>O</td>
    </tr>
    <tr>
        <td>Q</td>
        <td>R</td>
        <td>S</td>
        <td>T</td>
    </tr>
    
    <tr>
        <td class='rotate' rowspan="4"><div>20 kilograms</div></td>
        <td>B</td>
        <td>C</td>
        <td>D</td>
        <td>E</td>
    </tr>
    <tr>
        <td>G</td>
        <td>H</td>
        <td>I</td>
        <td>J</td>
    </tr>
    <tr>
        <td>L</td>
        <td>M</td>
        <td>N</td>
        <td>O</td>
    </tr>
    <tr>
        <td>Q</td>
        <td>R</td>
        <td>S</td>
        <td>T</td>
    </tr>
    
    <tr>
        <td class='rotate' rowspan="4"><div>30 kilograms</div></td>
        <td>B</td>
        <td>C</td>
        <td>D</td>
        <td>E</td>
    </tr>
    <tr>
        <td>G</td>
        <td>H</td>
        <td>I</td>
        <td>J</td>
    </tr>
    <tr>
        <td>L</td>
        <td>M</td>
        <td>N</td>
        <td>O</td>
    </tr>
    <tr>
        <td>Q</td>
        <td>R</td>
        <td>S</td>
        <td>T</td>
    </tr>
    
</table>

One thing to keep in mind with this solution is that it does not work well if the height of the row (or spanned rows) is shorter than the vertical text in the first column. It works best if you're spanning multiple rows or you have a lot of content creating tall rows.

Have fun playing around with this on jsFiddle.

Community
  • 1
  • 1
  • As a note: I bumped up the `margin-left` and `margin-right` values from `-10em` to `-100em` just to be on the safe side. If your un-rotated text width exceeds `20em`, the layout would begin to change. OTOH, `200em` width of text is far too much to read rotated by -90deg, so it should be sufficient to avoid running into this issue. – maxathousand Dec 28 '17 at 15:47
  • ^^ My fix above caused excessive white space below my table, due to the margins extending pretty wide (or "tall" after it was rotated). To fix that, I added `overflow: hidden` to the rotated `td`. – maxathousand Jan 05 '18 at 14:24
  • 1
    Not working on IE11. You should also add 'transform' and '-ms-transform' – Anonymoose Feb 14 '18 at 07:47
2

Unfortunately while I thought these answers may have worked for me, I struggled with a solution, as I'm using tables inside responsive tables - where the overflow-x is played with.

So, with that in mind, have a look at this link for a cleaner way, which doesn't have the weird width overflow issues. It worked for me in the end and was very easy to implement.

https://css-tricks.com/rotated-table-column-headers/

vr_driver
  • 1,867
  • 28
  • 39