35

This looks like it should be possible with the following:

.verticalText 
{           
    /* IE-only DX filter */
    writing-mode: tb-rl;
    filter: flipv fliph;

    /* Safari/Chrome function */
    -webkit-transform: rotate(270deg);

    /* works in latest FX builds */
    -moz-transform: rotate(270deg);
}

This works in IE.

It goes wrong in a bizarre way in Safari, Chrome and FX - the cell's size is calculated before the text is rotated!

screenshot of bug

Here is a demo: http://jsfiddle.net/HSKws/

I'm using dynamic images as a workaround, although that also has its problems. I'm happy with that as a fall-back, but it seems like there should be a way to make this CSS work - it's almost there.

Anyone know a way to make the cells fit the content after the transform has been applied?

Community
  • 1
  • 1
Keith
  • 150,284
  • 78
  • 298
  • 434
  • in FF3, the headers aren't rotated (is your test page set up correctly? There are no CSS styles to "vertical" class", but it might be because the CSS isn't valid for FF3) – Russ Cam Apr 04 '09 at 12:49
  • Apologies - can see the styles set up in the markup, they just don't appear in the right-hand CSS pane in Firebug – Russ Cam Apr 04 '09 at 12:50
  • 1
    Doesn't work in FF3 because it isn't supported until FF3.5 according to the developer docs. https://developer.mozilla.org/En/CSS/-moz-transform – AnthonyWJones Apr 04 '09 at 12:56
  • Yeah, sorry. I mentioned it in the code comments but wasn't clear. FX only supports CSS transforms in the latest preview releases. – Keith Apr 04 '09 at 14:18

6 Answers6

18

‘transform’ alters the orientation of the entire element you declare it on, not the text content inside it. It's more like IE's ‘matrix’ property than ‘writing-mode’.

Crucially, transforming an element doesn't change how its content size is calculated (or how its parent's layout is affected by that size). CSS's algorithms for vertical and horizontal sizing are different and difficult enough to get right to being with; there's no real consistent way they could accomodate content with arbitrary rotation. So ‘transform’ is like using ‘position: relative’: it changes where the content is rendered, but not anything to do with layout size.

So if you want to include one in a table you'll need to set the cell's ‘height’ explicitly to accomodate the expected rotated ‘width’. If you don't know that in advance you could potentially hack it up with JavaScript, perhaps.

FWIW: for me on Fx3.1b3 the span is also rotated like the others. However on Windows with its horizontal-only anti-aliasing (ClearType) the rendering doesn't look great... a well-rendered image could come out considerably better.

bobince
  • 528,062
  • 107
  • 651
  • 834
10

It's possible using inline SVG in a XHTML document (I only tested Safari and Firefox):

<html xmlns="http://www.w3.org/1999/xhtml">
  <body>
    <table border="1">
        <tr>
            <td>&#160;</td>
            <td>
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="150">
                  <text id="thetext" transform="rotate(270, 12, 0) translate(-140,0)">Example column header</text>
                </svg>
            </td>
            <td>
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="150">
                  <text id="thetext" transform="rotate(270, 12, 0) translate(-140,0)">Example column header</text>
                </svg>
            </td>
            <td>
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="150">
                  <text id="thetext" transform="rotate(270, 12, 0) translate(-140,0)">Example column header</text>
                </svg>
            </td>
        </tr>
        <tr>
            <td>Example row header</td>
            <td>1</td>
            <td>2</td>
            <td>3</td>
        </tr>
    </table>
  </body>
</html>

Unfortunately, you do have to explicitly set the width and height of your table cells and the translation of the text rendered using SVG. Also, the file extension must be xhtml.

otto.poellath
  • 4,129
  • 6
  • 45
  • 60
  • 1
    That's a good idea. I could also use a Javascript Canvas. However in both cases I need to explicitly set the width and height of the cells - if I could do that the CSS transform could be made to work too. My problem is that I don't know the exact size of the text in these cells; I need them to stretch to fit the content. – Keith Aug 20 '10 at 08:35
  • @AH: You need to set a doctype. Works in IE9, just tested ;) But doesn't work in IE8- – Stefan Steiger Oct 12 '12 at 10:55
8

Webkit has added:

-webkit-writing-mode:vertical-rl;

Which you can apply to a div.

Stephen Denne
  • 36,219
  • 10
  • 45
  • 60
6

As I answered on a similar question, I solved it this using a jQuery plugin by David Votrubec and the comment by Mike below the blog post.

Put this in a .js-file:

(function ($) {
  $.fn.rotateTableCellContent = function (options) {
  /*
Version 1.0
7/2011
Written by David Votrubec (davidjs.com) and
Michal Tehnik (@Mictech) for ST-Software.com
*/

var cssClass = ((options) ? options.className : false) || "vertical";

var cellsToRotate = $('.' + cssClass, this);

var betterCells = [];
cellsToRotate.each(function () {
var cell = $(this)
, newText = cell.text()
, height = cell.height()
, width = cell.width()
, newDiv = $('<div>', { height: width, width: height })
, newInnerDiv = $('<div>', { text: newText, 'class': 'rotated' });

newInnerDiv.css('-webkit-transform-origin', (width / 2) + 'px ' + (width / 2) + 'px');
newInnerDiv.css('-moz-transform-origin', (width / 2) + 'px ' + (width / 2) + 'px');
newDiv.append(newInnerDiv);

betterCells.push(newDiv);
});

cellsToRotate.each(function (i) {
$(this).html(betterCells[i]);
});
};
})(jQuery);

And this at the top of your page:

<script src="rotatetablecellcontent.js" type="text/javascript"></script>
<script type="text/javascript">
    $(document).ready(function(){
        $('.yourtableclass').rotateTableCellContent();
    });
</script>

And this in your CSS:

/* Styles for rotateTableCellContent plugin*/
table div.rotated {
    -webkit-transform: rotate(270deg);
    -moz-transform: rotate(270deg);
    writing-mode:tb-rl;
    white-space: nowrap;
}

thead th {
    vertical-align: top;
}

table .vertical {
    white-space: nowrap;
}

Then make sure your table has the class "yourtableclass", and that all the TDs you want rotated have the class "vertical".

Here's a demo running in a jsFiddle.

Hope it helps someone, even though I'm two years late!

Community
  • 1
  • 1
4

In order to have rotated text inside your table headers:

  1. Place the header content inside divs - rotate these divs rather than the header itself
  2. Set the position:relative on the table headers th, position:absolute on the rotated divs.
  3. Set height of th headers too

Done.

You can see it here:

enter image description here

Which you can see on this page if you make your window skinny - less than 1000 pixels and it rotates the table headers - http://www.rugbydata.com/

Here's the code I used:

div.rotatabletext {
-webkit-transform: rotate(-90deg);
/* Firefox */
-moz-transform: rotate(-90deg);
/* IE */
-ms-transform: rotate(-90deg);
/* Opera */
-o-transform: rotate(-90deg);
/* Internet Explorer */
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
width:0px;
text-align:left;
height:0px;
margin-left:0px;
margin-top:0px;
bottom:2px;
position:absolute;
}
table.tournamentresults > * > tr > td {
padding:1px;
}
table.tournamentresults > thead > tr:nth-child(1) > th:nth-child(1) {
height:70px;
position:relative;
}
table.tournamentresults > thead > tr:nth-child(2) th {
height:70px;
position:relative;
}
Dave Hilditch
  • 5,299
  • 4
  • 27
  • 35
3

This tool did all the thinking for me...

http://www.boogdesign.com/examples/transforms/matrix-calculator.html

doublejosh
  • 5,548
  • 4
  • 39
  • 45