Google analytics script

Latest jQuery CDN with code tiggling.

Tuesday, 2 August 2011

Cross browser headers with vertical rotated text

You've probably come across the problem of displaying these kind of tables:

  • many columns
  • header column at the top
  • content cells display narrow data - flags (yes/no, true/false, y/n, on/off, finite states like yes/no/maybe etc.) or just icons that denote some sort of state as in feature list tables where each cell displays either a check-mark or nothing or green and empty cirles or similar...
  • header cells contain much wider data than content cells - more words that take much valuable horizontal space
If you had to display these kind of tables you've probably been thinking how could you make header cells narrower but not clip their content so headers still make sense... The idea is to display header cells as tall cells with vertically displayed text so columns can stay narrow as their content cells need. This way our tables get horizontally usable and don't take much space. It's true that header row becomes higher (depending on the amount fo text that you'd like to display, but hey there's just one header row in the whole table.

Anyway. So if you did struggle with this and also wanted it to display approximately the same on all three major nowadays browsers than you did spend some time solving it. If you didn't but you think you may in the future, then just use the code I'll provide here and off you go.

Why is it such a problem?

As always the main problem lies in the fact that Internet Explorer has to work completely differently compared to other browsers. Even though developers ranted about this fact for years Microsoft never really managed to completely catch up to specification or competition. It's kind of like the Achilles and the tortoise paradox really but unfortunately in reality they really seem to always stay behind. The same is still true with their latest version 9 (latest as of August 2011). Their CSS3 support is still missing. They should at least implement what competition did, because no browser is perfect. But it's still better to be as good as your competition than worse. Because in the end you'll just be worse.

Why is rotation not enough?

CSS3 defines transform property which is nicely supported in Mozilla (Firefox) and Webkit (Chrome and Safari) browsers. You can set transform rotation and your element will render rotated as you desire. But that is not just as simple as you may think it is. No. Element's space will still be determined as if it wasn't rotated at all so it will seemingly still take just one line height (or 1em). If you're rotating more than 1em wide amount of text your rotated element will be rendered above your other content. That's why it's best to contain your rotated element within another container that is sized in the correct (vertical) dimensions. So it will be height as much as you need it to be and wide 1em (or more if you need it to be wider). Visually your rotated element will take just as much space as it needs because it's container sets its dimensions so other content will correctly flow around as per definition.

But there's more problems with Internet Explorer that doesn't work as nicely as other browsers. IE version 9 supports CSS3 transforms all right, but I'm not as lucky with my users so I have to support version 8 as well. Hence I rather provide a solution for IE that works equally well in both versions than a separate solution for each. That's why I have to resort to filters for IE.

Resulting HTML and stylesheet

Let's write a simple example that we can reuse whenever we need to display vertical text in your markup. This is our HTML with two vertical headers and some text before and after:

   1:  Some text before
   2:  <div class="container">
   3:      <div class="head">
   4:          <div class="vert">Vertical text example</div>
   5:      </div>
   6:      <div class="head">
   7:          <div class="vert">Vertical text example</div>
   8:      </div>
   9:  </div>
  10:  Some text after

CSS settings have to be this way (I've put extensinve comments inside so you will now what to change to suit your needs):

   1:  .container
   2:  {
   3:      /* this will give container dimension, because floated child nodes don't give any */
   4:      /* if your child nodes are inline-blocked, then you don't have to set it */
   5:      overflow: auto;
   6:  }
   7:      .container .head
   8:      {
   9:          /* float your elements or inline-block them to display side by side */
  10:          float: left;
  11:          /* these are height and width dimensions of your header */
  12:          height: 10em;
  13:          width: 1.5em;
  14:          /* set to hidden so when there's too much vertical text it will be clipped. */
  15:          overflow: hidden;
  16:          
  17:          /* these are not relevant and are here to better see the elements */
  18:          background: #eee;
  19:          margin-right: 1px;
  20:      }
  21:          .container .head .vert
  22:          {
  23:              /* line height should be equal to header width so text will be middle aligned */
  24:              line-height: 1.5em;
  25:              /* setting background may yield better results in IE text clear type rendering */
  26:              background: #eee;
  27:              display: block;
  28:              
  29:              /* this will prevent it from wrapping too much text */
  30:              white-space: nowrap;
  31:              /* so it stays off the edge */
  32:              padding-left: 3px;
  33:   
  34:              /* IE specific rotation code */
  35:              writing-mode: tb-rl;
  36:              filter: flipv fliph;
  37:              
  38:              /* CSS3 specific totation code */
  39:              /* translate should have the same negative dimension as head height */
  40:              transform: rotate(270deg) translate(-10em,0);
  41:              transform-origin: 0 0;
  42:              -moz-transform: rotate(270deg) translate(-10em,0);
  43:              -moz-transform-origin: 0 0;
  44:              -webkit-transform: rotate(270deg) translate(-10em,0);
  45:              -webkit-transform-origin: 0 0;
  46:          }

Example based on upper code

Lets see how it works:

Vertical text
Vertical text

Reuse at your own will and please suggest better alternatives

It took me some time to make this a browser wide solution (that also works in IE8) but here it is. If you need it, just copy the code and do whatever you please with it. If you have any suggestion of how to do the same thing better and easier (and maybe even more browser wide) then please leave a comment so I'll learn new things.

25 comments:

  1. Thanks, this works excellent!

    ReplyDelete
  2. This sol is not working fine in chrome and firefox.In these two browsers it is rotating the text properly but if the text is having only 25 characters but for longer text it is not working .
    Plz let me know if anyone is having this problems sol

    ReplyDelete
    Replies
    1. You have to of course resize elements to display longer text. This technique doesn't work with arbitrary long strings, but with predefined size only.

      Above example shows boxes of 9.5em high (container is 0.5em larger). If you'd like to display longer texts, resize accordingly so it fits your text...

      Is this the problem you're having or is it something else?

      Delete
  3. Thank you for your quick response.I got the solution.
    For that problem I have added two more lines
    top:95px;
    position:relative;

    Now it is coming fine in other browsers also.

    ReplyDelete
  4. Hello, the solution is elegant :). I have a little question. In IE 8 text is aligned to top of table header (I use it in "th" in a table) and not to bottom.
    How can I change vertical align for me?
    Many thanks for reply.

    ReplyDelete
    Replies
    1. I've checked in IE8 display mode and it seem to be aligned to the bottom. Can you please provide a JSFiddle so we can talk about concrete example that you're having?

      Delete
    2. Thanks for quickly answer. I've tested it now on JSFiddle and it seems good. Strange. I've pasted my html code under http://pastebin.com/9GwrGbH6. Screenshot for my example is under http://s18.postimage.org/ef8v6lcx5/vertical_text.png available.
      The problem is only in IE 8. Chrome, Firefox show all right.

      Thanks for your time, that you spend and sorry for my uggly english :).

      Delete
    3. When I test your Pastebin code I can see an issue only in IE7 mode, but not in IE8. Strangely enough when I do the same with this blog post, vertical text always display as it should. In any IE mode that is.
      You should look for differences between CSS presented on this post and in your code. And one more thing. You're using tables, so there's no need for float: left style setting. When you write CSS for your vertical text make sure that you understand it completely because that's the only way to make it reliable.

      Delete
    4. I've tested it again and found that I have not "DOCTYPE"-tag in my html. That was the solution of my problem.

      Many thanks again for your brilliant solution with vertical text in html.

      Bye!

      Delete
    5. I'm glad you've found the problem. Thanks for the info for any future visitors that may face the same problem.

      Delete
  5. I have a table with some long header names. Can this work with tables also?

    ReplyDelete
    Replies
    1. Of course it can, as long as you change some CSS styles accordingly. For instance float:left should be omitted from .container .head because your headers are already side by side... But apart from that I suppose it should work as is.

      Delete
  6. IE works great but its not working correctly in firefox. Any chance you can add a tables example?

    ReplyDelete
    Replies
    1. Could it be that you're having similar issues as the last commentator, that didn't set HTML DOCTYPE correctly? Can you also check that?

      How about elements displayed in this blog post? Do they display as expected in all browsers that you require?

      Delete
    2. DOCTYPE is being set. The div example displays ok in both browsers, but the table version doesnt display properly in Firefox (IE works perfectly). In Firefox the width of the box looks the same as the height despite forcing the cell width to be 25px wide.

      Here is a sample code

      .container {
      /* this will give container dimension, because floated child nodes don't give any */
      /* if your child nodes are inline-blocked, then you don't have to set it */
      overflow: auto;
      }
      .container .head {
      /* float your elements or inline-block them to display side by side */
      /*float: left;*/
      /* these are height and width dimensions of your header */
      height: 10em !important;
      width: 25px !important;
      /* set to hidden so when there's too much vertical text it will be clipped. */
      overflow: hidden;

      /* these are not relevant and are here to better see the elements */
      background: #eee;
      /*margin-right: 1px;*/
      vertical-align:baseline;
      }
      .container .head .vert {
      /* line height should be equal to header width so text will be middle aligned */
      line-height: 1.5em;
      /* setting background may yield better results in IE text clear type rendering */
      background: #eee;
      display: block;

      /* this will prevent it from wrapping too much text */
      white-space: nowrap;
      /* so it stays off the edge */
      padding-left: 3px;
      /* IE specific rotation code */
      writing-mode: tb-rl;
      filter: flipv fliph;
      /* CSS3 specific totation code */
      /* translate should have the same negative dimension as head height */
      transform: rotate(270deg) translate(-10em,0);
      transform-origin: 0 0;
      -moz-transform: rotate(270deg) translate(-10em,0);
      -moz-transform-origin: 0 0;
      -webkit-transform: rotate(270deg) translate(-10em,0);
      -webkit-transform-origin: 0 0;
      }

      <table class="ContentData_List fullwidth">
      <thead>
      <tr>
      <td colspan="5">Group heading </td>
      </tr>
      <tr class="container">
      <th class="head" nowrap><div class="vert">Skill 1</div></th>
      <th class="head" nowrap><div class="vert">Skill 2</div></th>
      <th class="head" nowrap><div class="vert">Skill 3</div></th>
      <th class="head" nowrap><div class="vert">Skill 4</div></th>
      <th class="head" nowrap><div class="vert">Skill 5</div></td>
      </tr>
      </thead>
      <tbody>
      <tr>
      <td>value 1</td>
      <td>value 2</td>
      <td>value 3</td>
      <td>value 4</td>
      <td>value 5</td>
      </tr>
      </tbody>
      </table>

      Any ideas?

      Delete
    3. I appreciate you sending over all this code but I suggest you rather put it into a JSFiddle so I can directly manipulate your code and test it on various browsers. And in the end also commit it for you to use.

      Would that be ok?

      Delete
  7. Hi,
    I want to have vertical table header for a table. So I tried tinkering with this solution a little bit. But I got a problem with the width of the td in the table body. The first cell has the width of all vertical headers. The following cells are attached to the end of the row.

    Could you please have a look at http://jsfiddle.net/Mrgaj/8/

    ReplyDelete
    Replies
    1. Well you've been playing just a little bit too much with your styles. You should keep table displays styles as they are, because otherwise if you don't change them all it will break your table as it did in your case.

      Check my updated version of your code:
      http://jsfiddle.net/Mrgaj/9/

      I haven't tested in various browsers but in Chrome it displays all right. You should tinker with it on other browsers, to make it work as expected if it doesn't already.

      Delete
  8. Hi,

    First of all : of all the methods I tried, this is the one that really works!
    Now, what I'd still like to see : how to use it with webfonts,
    and how to use it with jquery ( e.g. for handling hover )

    great script! ( -: roland :- )

    ReplyDelete
  9. hi,

    Very Good solution ..!! Appreciated .
    I have very tinny is issue the text is not coming in the middle of Div. It is on the top of it.
    i try
    /* float your elements or inline-block them to display side by side */
    float: left; to right . But there is not center ? if i go padding it increase col width . any idea ??

    ReplyDelete
  10. This script works great, first one I found that was easy and simple.

    I am having one problem however, the text does not go vertical in IE 10.

    Here is my page - http://hoffcomm.com/mc/chart/

    Is there is a quick fix to this?

    Any help is appreciated, thanks.

    ReplyDelete
  11. BHAVA THANK YOU BAHVA, THIS WORKED FOR ME........

    ReplyDelete
  12. It worked for me. Thank you very much

    ReplyDelete
  13. In IE10 and IE9, it is not working. IE8 and for other browsers it is working fine.

    ReplyDelete
    Replies
    1. Have you tried adding -ms-transform styles? IE9 requires those, but IE10 doesn't. I'm not sure what exactly doesn't work for you, but it may be that IE9+ is applying transforms as well as older stuff so it does too much. Play with it a bit.

      Delete