Rotated text

Once I al­ready shared this so­lu­tion on twit­ter, but this time I’m go­ing to write a bit more on it.

The task is to get the text ro­tated by 90 de­grees.

The prob­lem: it’s widely known that when you use trans­form, the block be­haves sim­i­lar to the po­si­tion:rel­a­tive —its place in the flow is not changed af­ter the trans­for­ma­tion, so the change is only visual.

How­ever, rather of­ten you’ll need to ro­tate the block in a way the flow would change ei­ther. Like if we’d want to put some ro­tated blocks in a row, or if we’d want to have ver­ti­cal head­ers in ta­bles —in those cases we would need the height of the block to be its width af­ter the ro­tate and vice versa.

I man­aged to make this work with one as­sump­tion —we would need to know the height of the ro­tated el­e­ment. In such case the so­lu­tion would be rather simple:

  1. We would need to have an ex­tra el­e­ment. HTML for each block would be like this:

     <span class="rotated-text">
         <span class="rotated-text__inner">
             Rotated foo
  2. Wrap­per would get those styles:

     .rotated-text {
         display: inline-block;
         overflow: hidden;
         width: 1.5em;
         line-height: 1.5;

    Here we make our el­e­ment to be in­line-block (that’s not crit­i­cal, the block dis­play would work too, but in­line-block is of­ten hand­ier), then we re­move all the ex­tra things us­ing over­flow (we would need this later) and set the width to the cur­rent el­e­ments’ height —the men­tioned as­sump­tion (and line-height is placed here as an ex­am­ple of what de­fines the blocks’ height).

  3. Then we make the in­ner el­e­ment to be in­line-block too, so its width would be col­lapsed to its con­tent. Af­ter this we make it have white-space:nowrap, so noth­ing would wrap (be­cause of the fixed width in the pre­vi­ous step), and then we ac­tu­ally ro­tate the block from the left top cor­ner us­ing trans­form-ori­gin (for read­abil­ity the trans­form prop­er­ties are given with­out proper pre­fixes):

     .rotated-text__inner {
         display: inline-block;
         white-space: nowrap;
         transform: translate(0,100%) rotate(-90deg);
         transform-origin: 0 0;
  4. And now the key part of my so­lu­tion: we need to make this in­ner el­e­ment to be square —this would make the re­sult­ing el­e­ment to have the height of its width, and the width would be equal to the as­sumed height on the wrap­per. So, to make an el­e­ment squar­ish we use this trick:

     .rotated-text__inner:after {
         content: "";
         float: left;
         margin-top: 100%;

    Not that hard, but not a lot of peo­ple re­mem­ber that top and bot­tom paddings and mar­gins set in per­cents are us­ing the width of the par­ent el­e­ment, not its height. This be­hav­ior is not widely used, but here is a case where it’s use­ful at last.

So, in the end we got a square el­e­ment, whose width is hid­den by the over­flow on wrap­per and this el­e­ment could be used in any con­text, so it would be af­fected by text-align or ver­ti­cal-align. It is rather “fair” ro­tated block.

And just some ba­sic ex­am­ples of usage:

Table headers

An ob­vi­ous ex­am­ple —com­pact table head­ers what don’t take that much of hor­i­zon­tal space:

First th Some cell And another
Second th 12 12314
Third th 12 12314
First th The Second th Third th
2 4 42
12 4 234
13 100 0


As all the ro­tated blocks have fair place in a flow, you could arrange them in a row so they won’t over­lap each other and the height of the whole row would be equal to the “high­est” of them:

So, that’s it.

Once again: we need to know the ini­tial height of the ro­tated block, so if we’d need to ro­tate mul­ti­line blocks, we’d need to change their re­sult­ing width ac­cord­ingly.

Also, this method could work in IE —by adding ma­trix fil­ter and con­vert­ing a pseudo-el­e­ment to an ac­tual one —but I’m lazy enough to do this. But if you’d like, you could make it by your­self and even sub­mit a Pull Re­quests to those ex­am­ples :)