[html] Vertical (rotated) text in HTML table

Is there a (portable) way to rotate text in a HTML table cell by 90°?

(I have a table with many columns and much text for the headings, so I'd like to write it vertically to save space.)

This question is related to html css text-rendering text-styling

The answer is


_x000D_
_x000D_
.box_rotate {_x000D_
     -moz-transform: rotate(7.5deg);  /* FF3.5+ */_x000D_
       -o-transform: rotate(7.5deg);  /* Opera 10.5 */_x000D_
  -webkit-transform: rotate(7.5deg);  /* Saf3.1+, Chrome */_x000D_
             filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083);  /* IE6,IE7 */_x000D_
         -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)"; /* IE8 */_x000D_
    }
_x000D_
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vitae porta lectus. Suspendisse dolor mauris, scelerisque ut diam vitae, dictum ultricies est. Cras sit amet erat porttitor arcu lacinia ultricies. Morbi sodales, nisl vitae imperdiet consequat, purus nunc maximus nulla, et pharetra dolor ex non dolor.</div>_x000D_
<div class="box_rotate">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vitae porta lectus. Suspendisse dolor mauris, scelerisque ut diam vitae, dictum ultricies est. Cras sit amet erat porttitor arcu lacinia ultricies. Morbi sodales, nisl vitae imperdiet consequat, purus nunc maximus nulla, et pharetra dolor ex non dolor.</div>_x000D_
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vitae porta lectus. Suspendisse dolor mauris, scelerisque ut diam vitae, dictum ultricies est. Cras sit amet erat porttitor arcu lacinia ultricies. Morbi sodales, nisl vitae imperdiet consequat, purus nunc maximus nulla, et pharetra dolor ex non dolor.</div>
_x000D_
_x000D_
_x000D_

Taken from http://css3please.com/

As of 2017, the aforementioned site has simplified the rule set to drop legacy Internet Explorer filter and rely more in the now standard transform property:

_x000D_
_x000D_
.box_rotate {_x000D_
  -webkit-transform: rotate(7.5deg);  /* Chrome, Opera 15+, Safari 3.1+ */_x000D_
      -ms-transform: rotate(7.5deg);  /* IE 9 */_x000D_
          transform: rotate(7.5deg);  /* Firefox 16+, IE 10+, Opera */_x000D_
}
_x000D_
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vitae porta lectus. Suspendisse dolor mauris, scelerisque ut diam vitae, dictum ultricies est. Cras sit amet erat porttitor arcu lacinia ultricies. Morbi sodales, nisl vitae imperdiet consequat, purus nunc maximus nulla, et pharetra dolor ex non dolor.</div>_x000D_
<div class="box_rotate">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vitae porta lectus. Suspendisse dolor mauris, scelerisque ut diam vitae, dictum ultricies est. Cras sit amet erat porttitor arcu lacinia ultricies. Morbi sodales, nisl vitae imperdiet consequat, purus nunc maximus nulla, et pharetra dolor ex non dolor.</div>_x000D_
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vitae porta lectus. Suspendisse dolor mauris, scelerisque ut diam vitae, dictum ultricies est. Cras sit amet erat porttitor arcu lacinia ultricies. Morbi sodales, nisl vitae imperdiet consequat, purus nunc maximus nulla, et pharetra dolor ex non dolor.</div>
_x000D_
_x000D_
_x000D_


I was using the Font Awesome library and was able to achieve this affect by tacking on the following to any html element.

<div class="fa fa-rotate-270">
  My Test Text
</div>

Your mileage may vary.


IE filters plus CSS transforms (Safari and Firefox).

IE's support is the oldest, Safari has [at least some?] support in 3.1.2, and Firefox won't have support until 3.1.

Alternatively, I would recommend a mix of Canvas/VML or SVG/VML. (Canvas has wider support.)


I was using the Font Awesome library and was able to achieve this affect by tacking on the following to any html element.

<div class="fa fa-rotate-270">
  My Test Text
</div>

Your mileage may vary.


Alternate Solution?

Instead of rotating the text, would it work to have it written "top to bottom?"

Like this:

S  
O  
M  
E  

T  
E  
X  
T  

I think that would be a lot easier - you can pick a string of text apart and insert a line break after each character.

This could be done via JavaScript in the browser like this:

"SOME TEXT".split("").join("\n")

... or you could do it server-side, so it wouldn't depend on the client's JS capabilities. (I assume that's what you mean by "portable?")

Also the user doesn't have to turn his/her head sideways to read it. :)

Update

This thread is about doing this with jQuery.


Have a look at this, i found this while looking for a solution for IE 7.

totally a cool solution for css only vibes

Thanks aiboy for the soultion

heres the link

and here is the stack-overflow link where i came across this link meow

         .vertical-text-vibes{

                /* this is for shity "non IE" browsers
                   that dosn't support writing-mode */
                -webkit-transform: translate(1.1em,0) rotate(90deg);
                   -moz-transform: translate(1.1em,0) rotate(90deg);
                     -o-transform: translate(1.1em,0) rotate(90deg);
                        transform: translate(1.1em,0) rotate(90deg);
                -webkit-transform-origin: 0 0;
                   -moz-transform-origin: 0 0;
                     -o-transform-origin: 0 0;
                        transform-origin: 0 0;  
             /* IE9+ */    ms-transform: none;    
                   -ms-transform-origin: none;    
        /* IE8+ */    -ms-writing-mode: tb-rl;    
   /* IE7 and below */    *writing-mode: tb-rl;

            }

Alternate Solution?

Instead of rotating the text, would it work to have it written "top to bottom?"

Like this:

S  
O  
M  
E  

T  
E  
X  
T  

I think that would be a lot easier - you can pick a string of text apart and insert a line break after each character.

This could be done via JavaScript in the browser like this:

"SOME TEXT".split("").join("\n")

... or you could do it server-side, so it wouldn't depend on the client's JS capabilities. (I assume that's what you mean by "portable?")

Also the user doesn't have to turn his/her head sideways to read it. :)

Update

This thread is about doing this with jQuery.


After having tried for over two hours, I can safely say that all the method mentioned so far don't work across browsers, or for IE even across browser versions...

For example (top upvoted answer):

 filter:  progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083);  /* IE6,IE7 */
     -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)"; /* IE8 */

rotates twice in IE9, once for filter, and once for -ms-filter, so...

All other mentioned methods do not work either, at least not if you have to set no fixed height/width of the table header cell (with background color), where it should automatically adjust to size of the highest element.

So to elaborate on the server-side image generation proposed by Nathan Long, which is really the only universially working method, here my VB.NET code for a generic handler (*.ashx ):

Imports System.Web
Imports System.Web.Services


Public Class GenerateImage
    Implements System.Web.IHttpHandler


    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        'context.Response.ContentType = "text/plain"
        'context.Response.Write("Hello World!")
        context.Response.ContentType = "image/png"

        Dim strText As String = context.Request.QueryString("text")
        Dim strRotate As String = context.Request.QueryString("rotate")
        Dim strBGcolor As String = context.Request.QueryString("bgcolor")

        Dim bRotate As Boolean = True

        If String.IsNullOrEmpty(strText) Then
            strText = "No Text"
        End If


        Try
            If Not String.IsNullOrEmpty(strRotate) Then
                bRotate = System.Convert.ToBoolean(strRotate)
            End If
        Catch ex As Exception

        End Try


        'Dim img As System.Drawing.Image = GenerateImage(strText, "Arial", bRotate)
        'Dim img As System.Drawing.Image = CreateBitmapImage(strText, bRotate)

        ' Generic error in GDI+
        'img.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Png)

        'Dim bm As System.Drawing.Bitmap = New System.Drawing.Bitmap(img)
        'bm.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Png)

        Using msTempOutputStream As New System.IO.MemoryStream
            'Dim img As System.Drawing.Image = GenerateImage(strText, "Arial", bRotate)
            Using img As System.Drawing.Image = CreateBitmapImage(strText, bRotate, strBGcolor)
                img.Save(msTempOutputStream, System.Drawing.Imaging.ImageFormat.Png)
                msTempOutputStream.Flush()

                context.Response.Buffer = True
                context.Response.ContentType = "image/png"
                context.Response.BinaryWrite(msTempOutputStream.ToArray())
            End Using ' img

        End Using ' msTempOutputStream

    End Sub ' ProcessRequest


    Private Function CreateBitmapImage(strImageText As String) As System.Drawing.Image
        Return CreateBitmapImage(strImageText, True)
    End Function ' CreateBitmapImage


    Private Function CreateBitmapImage(strImageText As String, bRotate As Boolean) As System.Drawing.Image
        Return CreateBitmapImage(strImageText, bRotate, Nothing)
    End Function


    Private Function InvertMeAColour(ColourToInvert As System.Drawing.Color) As System.Drawing.Color
        Const RGBMAX As Integer = 255
        Return System.Drawing.Color.FromArgb(RGBMAX - ColourToInvert.R, RGBMAX - ColourToInvert.G, RGBMAX - ColourToInvert.B)
    End Function



    Private Function CreateBitmapImage(strImageText As String, bRotate As Boolean, strBackgroundColor As String) As System.Drawing.Image
        Dim bmpEndImage As System.Drawing.Bitmap = Nothing

        If String.IsNullOrEmpty(strBackgroundColor) Then
            strBackgroundColor = "#E0E0E0"
        End If

        Dim intWidth As Integer = 0
        Dim intHeight As Integer = 0


        Dim bgColor As System.Drawing.Color = System.Drawing.Color.LemonChiffon ' LightGray
        bgColor = System.Drawing.ColorTranslator.FromHtml(strBackgroundColor)

        Dim TextColor As System.Drawing.Color = System.Drawing.Color.Black
        TextColor = InvertMeAColour(bgColor)

        'TextColor = Color.FromArgb(102, 102, 102)



        ' Create the Font object for the image text drawing.
        Using fntThisFont As New System.Drawing.Font("Arial", 11, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Pixel)

            ' Create a graphics object to measure the text's width and height.
            Using bmpInitialImage As New System.Drawing.Bitmap(1, 1)

                Using gStringMeasureGraphics As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmpInitialImage)
                    ' This is where the bitmap size is determined.
                    intWidth = CInt(gStringMeasureGraphics.MeasureString(strImageText, fntThisFont).Width)
                    intHeight = CInt(gStringMeasureGraphics.MeasureString(strImageText, fntThisFont).Height)

                    ' Create the bmpImage again with the correct size for the text and font.
                    bmpEndImage = New System.Drawing.Bitmap(bmpInitialImage, New System.Drawing.Size(intWidth, intHeight))

                    ' Add the colors to the new bitmap.
                    Using gNewGraphics As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmpEndImage)
                        ' Set Background color
                        'gNewGraphics.Clear(Color.White)
                        gNewGraphics.Clear(bgColor)
                        gNewGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias
                        gNewGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias


                        ''''

                        'gNewGraphics.TranslateTransform(bmpEndImage.Width, bmpEndImage.Height)
                        'gNewGraphics.RotateTransform(180)
                        'gNewGraphics.RotateTransform(0)
                        'gNewGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault


                        gNewGraphics.DrawString(strImageText, fntThisFont, New System.Drawing.SolidBrush(TextColor), 0, 0)

                        gNewGraphics.Flush()

                        If bRotate Then
                            'bmpEndImage = rotateImage(bmpEndImage, 90)
                            'bmpEndImage = RotateImage(bmpEndImage, New PointF(0, 0), 90)
                            'bmpEndImage.RotateFlip(RotateFlipType.Rotate90FlipNone)
                            bmpEndImage.RotateFlip(System.Drawing.RotateFlipType.Rotate270FlipNone)
                        End If ' bRotate

                    End Using ' gNewGraphics

                End Using ' gStringMeasureGraphics

            End Using ' bmpInitialImage

        End Using ' fntThisFont

        Return bmpEndImage
    End Function ' CreateBitmapImage


    ' http://msdn.microsoft.com/en-us/library/3zxbwxch.aspx
    ' http://msdn.microsoft.com/en-us/library/7e1w5dhw.aspx
    ' http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=286
    ' http://road-blogs.blogspot.com/2011/01/rotate-text-in-ssrs.html
    Public Shared Function GenerateImage_CrappyOldReportingServiceVariant(ByVal strText As String, ByVal strFont As String, bRotate As Boolean) As System.Drawing.Image
        Dim bgColor As System.Drawing.Color = System.Drawing.Color.LemonChiffon ' LightGray
        bgColor = System.Drawing.ColorTranslator.FromHtml("#E0E0E0")


        Dim TextColor As System.Drawing.Color = System.Drawing.Color.Black
        'TextColor = System.Drawing.Color.FromArgb(255, 0, 0, 255)

        If String.IsNullOrEmpty(strFont) Then
            strFont = "Arial"
        Else
            If strFont.Trim().Equals(String.Empty) Then
                strFont = "Arial"
            End If
        End If


        'Dim fsFontStyle As System.Drawing.FontStyle = System.Drawing.FontStyle.Regular
        Dim fsFontStyle As System.Drawing.FontStyle = System.Drawing.FontStyle.Bold
        Dim fontFamily As New System.Drawing.FontFamily(strFont)
        Dim iFontSize As Integer = 8 '//Change this as needed


        ' vice-versa, because 270° turn
        'Dim height As Double = 2.25
        Dim height As Double = 4
        Dim width As Double = 1

        ' width = 10
        ' height = 10

        Dim bmpImage As New System.Drawing.Bitmap(1, 1)
        Dim iHeight As Integer = CInt(height * 0.393700787 * bmpImage.VerticalResolution) 'y DPI
        Dim iWidth As Integer = CInt(width * 0.393700787 * bmpImage.HorizontalResolution) 'x DPI

        bmpImage = New System.Drawing.Bitmap(bmpImage, New System.Drawing.Size(iWidth, iHeight))



        '// Create the Font object for the image text drawing.
        'Dim MyFont As New System.Drawing.Font("Arial", iFontSize, fsFontStyle, System.Drawing.GraphicsUnit.Point)
        '// Create a graphics object to measure the text's width and height.
        Dim MyGraphics As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmpImage)
        MyGraphics.Clear(bgColor)


        Dim stringFormat As New System.Drawing.StringFormat()
        stringFormat.FormatFlags = System.Drawing.StringFormatFlags.DirectionVertical
        'stringFormat.FormatFlags = System.Drawing.StringFormatFlags.DirectionVertical Or System.Drawing.StringFormatFlags.DirectionRightToLeft
        Dim solidBrush As New System.Drawing.SolidBrush(TextColor)
        Dim pointF As New System.Drawing.PointF(CSng(iWidth / 2 - iFontSize / 2 - 2), 5)
        Dim font As New System.Drawing.Font(fontFamily, iFontSize, fsFontStyle, System.Drawing.GraphicsUnit.Point)


        MyGraphics.TranslateTransform(bmpImage.Width, bmpImage.Height)
        MyGraphics.RotateTransform(180)
        MyGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault
        MyGraphics.DrawString(strText, font, solidBrush, pointF, stringFormat)
        MyGraphics.ResetTransform()

        MyGraphics.Flush()

        'If Not bRotate Then
        'bmpImage.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone)
        'End If

        Return bmpImage
    End Function ' GenerateImage



    ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property ' IsReusable


End Class

Note that if you think that this part

        Using msTempOutputStream As New System.IO.MemoryStream
            'Dim img As System.Drawing.Image = GenerateImage(strText, "Arial", bRotate)
            Using img As System.Drawing.Image = CreateBitmapImage(strText, bRotate, strBGcolor)
                img.Save(msTempOutputStream, System.Drawing.Imaging.ImageFormat.Png)
                msTempOutputStream.Flush()

                context.Response.Buffer = True
                context.Response.ContentType = "image/png"
                context.Response.BinaryWrite(msTempOutputStream.ToArray())
            End Using ' img

        End Using ' msTempOutputStream

can be replaced with

img.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Png)

because it works on the development server, then you are sorely mistaken to assume the very same code wouldn't throw a Generic GDI+ exception if you deploy it to a Windows 2003 IIS 6 server...

then use it like this:

<img alt="bla" src="GenerateImage.ashx?no_cache=123&text=Hello%20World&rotate=true" />

My first contribution to the community , example as rotating a simple text and the header of a table, only using html and css.

enter image description here

HTML

<div class="rotate">text</div>

CSS

.rotate {
  display:inline-block;
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
  -webkit-transform: rotate(270deg);
  -ms-transform: rotate(270deg);
  transform: rotate(270deg);
}

Here an example in jsfiddle


IE filters plus CSS transforms (Safari and Firefox).

IE's support is the oldest, Safari has [at least some?] support in 3.1.2, and Firefox won't have support until 3.1.

Alternatively, I would recommend a mix of Canvas/VML or SVG/VML. (Canvas has wider support.)


-moz-transform: rotate(7.5deg);  /* FF3.5+ */
-o-transform: rotate(7.5deg);  /* Opera 10.5 */
-webkit-transform: rotate(7.5deg);  /* Saf3.1+, Chrome */
filter:  progid:DXImageTransform.Microsoft.BasicImage(rotation=1);  /* IE6,IE7 allows only 1, 2, 3 */
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; /* IE8 allows only 1 2 or 3*/

After having tried for over two hours, I can safely say that all the method mentioned so far don't work across browsers, or for IE even across browser versions...

For example (top upvoted answer):

 filter:  progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083);  /* IE6,IE7 */
     -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)"; /* IE8 */

rotates twice in IE9, once for filter, and once for -ms-filter, so...

All other mentioned methods do not work either, at least not if you have to set no fixed height/width of the table header cell (with background color), where it should automatically adjust to size of the highest element.

So to elaborate on the server-side image generation proposed by Nathan Long, which is really the only universially working method, here my VB.NET code for a generic handler (*.ashx ):

Imports System.Web
Imports System.Web.Services


Public Class GenerateImage
    Implements System.Web.IHttpHandler


    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        'context.Response.ContentType = "text/plain"
        'context.Response.Write("Hello World!")
        context.Response.ContentType = "image/png"

        Dim strText As String = context.Request.QueryString("text")
        Dim strRotate As String = context.Request.QueryString("rotate")
        Dim strBGcolor As String = context.Request.QueryString("bgcolor")

        Dim bRotate As Boolean = True

        If String.IsNullOrEmpty(strText) Then
            strText = "No Text"
        End If


        Try
            If Not String.IsNullOrEmpty(strRotate) Then
                bRotate = System.Convert.ToBoolean(strRotate)
            End If
        Catch ex As Exception

        End Try


        'Dim img As System.Drawing.Image = GenerateImage(strText, "Arial", bRotate)
        'Dim img As System.Drawing.Image = CreateBitmapImage(strText, bRotate)

        ' Generic error in GDI+
        'img.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Png)

        'Dim bm As System.Drawing.Bitmap = New System.Drawing.Bitmap(img)
        'bm.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Png)

        Using msTempOutputStream As New System.IO.MemoryStream
            'Dim img As System.Drawing.Image = GenerateImage(strText, "Arial", bRotate)
            Using img As System.Drawing.Image = CreateBitmapImage(strText, bRotate, strBGcolor)
                img.Save(msTempOutputStream, System.Drawing.Imaging.ImageFormat.Png)
                msTempOutputStream.Flush()

                context.Response.Buffer = True
                context.Response.ContentType = "image/png"
                context.Response.BinaryWrite(msTempOutputStream.ToArray())
            End Using ' img

        End Using ' msTempOutputStream

    End Sub ' ProcessRequest


    Private Function CreateBitmapImage(strImageText As String) As System.Drawing.Image
        Return CreateBitmapImage(strImageText, True)
    End Function ' CreateBitmapImage


    Private Function CreateBitmapImage(strImageText As String, bRotate As Boolean) As System.Drawing.Image
        Return CreateBitmapImage(strImageText, bRotate, Nothing)
    End Function


    Private Function InvertMeAColour(ColourToInvert As System.Drawing.Color) As System.Drawing.Color
        Const RGBMAX As Integer = 255
        Return System.Drawing.Color.FromArgb(RGBMAX - ColourToInvert.R, RGBMAX - ColourToInvert.G, RGBMAX - ColourToInvert.B)
    End Function



    Private Function CreateBitmapImage(strImageText As String, bRotate As Boolean, strBackgroundColor As String) As System.Drawing.Image
        Dim bmpEndImage As System.Drawing.Bitmap = Nothing

        If String.IsNullOrEmpty(strBackgroundColor) Then
            strBackgroundColor = "#E0E0E0"
        End If

        Dim intWidth As Integer = 0
        Dim intHeight As Integer = 0


        Dim bgColor As System.Drawing.Color = System.Drawing.Color.LemonChiffon ' LightGray
        bgColor = System.Drawing.ColorTranslator.FromHtml(strBackgroundColor)

        Dim TextColor As System.Drawing.Color = System.Drawing.Color.Black
        TextColor = InvertMeAColour(bgColor)

        'TextColor = Color.FromArgb(102, 102, 102)



        ' Create the Font object for the image text drawing.
        Using fntThisFont As New System.Drawing.Font("Arial", 11, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Pixel)

            ' Create a graphics object to measure the text's width and height.
            Using bmpInitialImage As New System.Drawing.Bitmap(1, 1)

                Using gStringMeasureGraphics As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmpInitialImage)
                    ' This is where the bitmap size is determined.
                    intWidth = CInt(gStringMeasureGraphics.MeasureString(strImageText, fntThisFont).Width)
                    intHeight = CInt(gStringMeasureGraphics.MeasureString(strImageText, fntThisFont).Height)

                    ' Create the bmpImage again with the correct size for the text and font.
                    bmpEndImage = New System.Drawing.Bitmap(bmpInitialImage, New System.Drawing.Size(intWidth, intHeight))

                    ' Add the colors to the new bitmap.
                    Using gNewGraphics As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmpEndImage)
                        ' Set Background color
                        'gNewGraphics.Clear(Color.White)
                        gNewGraphics.Clear(bgColor)
                        gNewGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias
                        gNewGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias


                        ''''

                        'gNewGraphics.TranslateTransform(bmpEndImage.Width, bmpEndImage.Height)
                        'gNewGraphics.RotateTransform(180)
                        'gNewGraphics.RotateTransform(0)
                        'gNewGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault


                        gNewGraphics.DrawString(strImageText, fntThisFont, New System.Drawing.SolidBrush(TextColor), 0, 0)

                        gNewGraphics.Flush()

                        If bRotate Then
                            'bmpEndImage = rotateImage(bmpEndImage, 90)
                            'bmpEndImage = RotateImage(bmpEndImage, New PointF(0, 0), 90)
                            'bmpEndImage.RotateFlip(RotateFlipType.Rotate90FlipNone)
                            bmpEndImage.RotateFlip(System.Drawing.RotateFlipType.Rotate270FlipNone)
                        End If ' bRotate

                    End Using ' gNewGraphics

                End Using ' gStringMeasureGraphics

            End Using ' bmpInitialImage

        End Using ' fntThisFont

        Return bmpEndImage
    End Function ' CreateBitmapImage


    ' http://msdn.microsoft.com/en-us/library/3zxbwxch.aspx
    ' http://msdn.microsoft.com/en-us/library/7e1w5dhw.aspx
    ' http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=286
    ' http://road-blogs.blogspot.com/2011/01/rotate-text-in-ssrs.html
    Public Shared Function GenerateImage_CrappyOldReportingServiceVariant(ByVal strText As String, ByVal strFont As String, bRotate As Boolean) As System.Drawing.Image
        Dim bgColor As System.Drawing.Color = System.Drawing.Color.LemonChiffon ' LightGray
        bgColor = System.Drawing.ColorTranslator.FromHtml("#E0E0E0")


        Dim TextColor As System.Drawing.Color = System.Drawing.Color.Black
        'TextColor = System.Drawing.Color.FromArgb(255, 0, 0, 255)

        If String.IsNullOrEmpty(strFont) Then
            strFont = "Arial"
        Else
            If strFont.Trim().Equals(String.Empty) Then
                strFont = "Arial"
            End If
        End If


        'Dim fsFontStyle As System.Drawing.FontStyle = System.Drawing.FontStyle.Regular
        Dim fsFontStyle As System.Drawing.FontStyle = System.Drawing.FontStyle.Bold
        Dim fontFamily As New System.Drawing.FontFamily(strFont)
        Dim iFontSize As Integer = 8 '//Change this as needed


        ' vice-versa, because 270° turn
        'Dim height As Double = 2.25
        Dim height As Double = 4
        Dim width As Double = 1

        ' width = 10
        ' height = 10

        Dim bmpImage As New System.Drawing.Bitmap(1, 1)
        Dim iHeight As Integer = CInt(height * 0.393700787 * bmpImage.VerticalResolution) 'y DPI
        Dim iWidth As Integer = CInt(width * 0.393700787 * bmpImage.HorizontalResolution) 'x DPI

        bmpImage = New System.Drawing.Bitmap(bmpImage, New System.Drawing.Size(iWidth, iHeight))



        '// Create the Font object for the image text drawing.
        'Dim MyFont As New System.Drawing.Font("Arial", iFontSize, fsFontStyle, System.Drawing.GraphicsUnit.Point)
        '// Create a graphics object to measure the text's width and height.
        Dim MyGraphics As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmpImage)
        MyGraphics.Clear(bgColor)


        Dim stringFormat As New System.Drawing.StringFormat()
        stringFormat.FormatFlags = System.Drawing.StringFormatFlags.DirectionVertical
        'stringFormat.FormatFlags = System.Drawing.StringFormatFlags.DirectionVertical Or System.Drawing.StringFormatFlags.DirectionRightToLeft
        Dim solidBrush As New System.Drawing.SolidBrush(TextColor)
        Dim pointF As New System.Drawing.PointF(CSng(iWidth / 2 - iFontSize / 2 - 2), 5)
        Dim font As New System.Drawing.Font(fontFamily, iFontSize, fsFontStyle, System.Drawing.GraphicsUnit.Point)


        MyGraphics.TranslateTransform(bmpImage.Width, bmpImage.Height)
        MyGraphics.RotateTransform(180)
        MyGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault
        MyGraphics.DrawString(strText, font, solidBrush, pointF, stringFormat)
        MyGraphics.ResetTransform()

        MyGraphics.Flush()

        'If Not bRotate Then
        'bmpImage.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone)
        'End If

        Return bmpImage
    End Function ' GenerateImage



    ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property ' IsReusable


End Class

Note that if you think that this part

        Using msTempOutputStream As New System.IO.MemoryStream
            'Dim img As System.Drawing.Image = GenerateImage(strText, "Arial", bRotate)
            Using img As System.Drawing.Image = CreateBitmapImage(strText, bRotate, strBGcolor)
                img.Save(msTempOutputStream, System.Drawing.Imaging.ImageFormat.Png)
                msTempOutputStream.Flush()

                context.Response.Buffer = True
                context.Response.ContentType = "image/png"
                context.Response.BinaryWrite(msTempOutputStream.ToArray())
            End Using ' img

        End Using ' msTempOutputStream

can be replaced with

img.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Png)

because it works on the development server, then you are sorely mistaken to assume the very same code wouldn't throw a Generic GDI+ exception if you deploy it to a Windows 2003 IIS 6 server...

then use it like this:

<img alt="bla" src="GenerateImage.ashx?no_cache=123&text=Hello%20World&rotate=true" />

-moz-transform: rotate(7.5deg);  /* FF3.5+ */
-o-transform: rotate(7.5deg);  /* Opera 10.5 */
-webkit-transform: rotate(7.5deg);  /* Saf3.1+, Chrome */
filter:  progid:DXImageTransform.Microsoft.BasicImage(rotation=1);  /* IE6,IE7 allows only 1, 2, 3 */
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; /* IE8 allows only 1 2 or 3*/

There is a quote in the original answer and my previous answer on the IE8 line that throws this off, right near the semi-colon. Yikes and BAAAAD! The code below has the rotation set correctly and works. You have to float in IE for the filter to be applied.

<div style="
    float: left; 
    position: relative;
    -moz-transform: rotate(270deg);  /* FF3.5+ */        
    -o-transform: rotate(270deg);  /* Opera 10.5 */   
    -webkit-transform: rotate(270deg);  /* Saf3.1+, Chrome */              
    filter:  progid:DXImageTransform.Microsoft.BasicImage(rotation=3);  /* IE6,IE7 */          
    -ms-filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); /* IE8 */           
"
>Count & Value</div>;

Here is one that works for plain-text with some server side processing:

public string RotateHtmltext(string innerHtml)
{
   const string TRANSFORMTEXT = "transform: rotate(90deg);";
   const string EXTRASTYLECSS = "<style type='text/css'>.r90 {"
                                 + "-webkit-" + TRANSFORMTEXT
                                 + "-moz-" + TRANSFORMTEXT
                                 + "-o-" + TRANSFORMTEXT
                                 + "-ms-" + TRANSFORMTEXT
                                 + "" + TRANSFORMTEXT
                                 + "width:1em;line-height:1ex}</style>";
   const string WRAPPERDIV = "<div style='display: table-cell; vertical-align: middle;'>";

   var newinnerHtml = string.Join("</div>"+WRAPPERDIV, Regex.Split(innerHtml, @"<br */?>").Reverse());

   newinnerHtml = Regex.Replace(newinnerHtml, @"((?:<[^>]*>)|(?:[^<]+))",
                                 match => match.Groups[1].Value.StartsWith("<")
                                             ? match.Groups[1].Value
                                             : string.Join("", match.Groups[1].Value.ToCharArray().Select(x=>"<div class='r90'>"+x+"</div>")),
                                 RegexOptions.Singleline);
   return EXTRASTYLECSS + WRAPPERDIV + newinnerHtml + "</div>";
}

which gives something like:

<style type="text/css">.r90 {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
width: 1em;
line-height: 1ex; 
}</style>
<div style="display: table-cell; vertical-align: middle;">
<div class="r90">p</div>
<div class="r90">o</div>
<div class="r90">s</div>
</div><div style="display: table-cell; vertical-align: middle;">
<div class="r90">(</div>
<div class="r90">A</div>
<div class="r90">b</div>
<div class="r90">s</div>
<div class="r90">)</div>
</div>

http://jsfiddle.net/TzzHy/


Alternate Solution?

Instead of rotating the text, would it work to have it written "top to bottom?"

Like this:

S  
O  
M  
E  

T  
E  
X  
T  

I think that would be a lot easier - you can pick a string of text apart and insert a line break after each character.

This could be done via JavaScript in the browser like this:

"SOME TEXT".split("").join("\n")

... or you could do it server-side, so it wouldn't depend on the client's JS capabilities. (I assume that's what you mean by "portable?")

Also the user doesn't have to turn his/her head sideways to read it. :)

Update

This thread is about doing this with jQuery.


IE filters plus CSS transforms (Safari and Firefox).

IE's support is the oldest, Safari has [at least some?] support in 3.1.2, and Firefox won't have support until 3.1.

Alternatively, I would recommend a mix of Canvas/VML or SVG/VML. (Canvas has wider support.)


Another solution:

(function () {

    var make_rotated_text = function (text)
    {
        var can = document.createElement ('canvas');
        can.width = 10;
        can.height = 10;
        var ctx=can.getContext ("2d");
        ctx.font="20px Verdana";
        var m = ctx.measureText(text);
        can.width = 20;
        can.height = m.width;
        ctx.font="20px Verdana";
        ctx.fillStyle = "#000000";
        ctx.rotate(90 * (Math.PI / 180));
        ctx.fillText (text, 0, -2);
        return can;
    };

    var canvas = make_rotated_text ("Hellooooo :D");
    var body = document.getElementsByTagName ('body')[0];
    body.appendChild (canvas);

}) ();

I do absolutely admit that this is quite hackish, but it's a simple solution if you want to avoid bloating your css.


My first contribution to the community , example as rotating a simple text and the header of a table, only using html and css.

enter image description here

HTML

<div class="rotate">text</div>

CSS

.rotate {
  display:inline-block;
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
  -webkit-transform: rotate(270deg);
  -ms-transform: rotate(270deg);
  transform: rotate(270deg);
}

Here an example in jsfiddle


Another solution:

(function () {

    var make_rotated_text = function (text)
    {
        var can = document.createElement ('canvas');
        can.width = 10;
        can.height = 10;
        var ctx=can.getContext ("2d");
        ctx.font="20px Verdana";
        var m = ctx.measureText(text);
        can.width = 20;
        can.height = m.width;
        ctx.font="20px Verdana";
        ctx.fillStyle = "#000000";
        ctx.rotate(90 * (Math.PI / 180));
        ctx.fillText (text, 0, -2);
        return can;
    };

    var canvas = make_rotated_text ("Hellooooo :D");
    var body = document.getElementsByTagName ('body')[0];
    body.appendChild (canvas);

}) ();

I do absolutely admit that this is quite hackish, but it's a simple solution if you want to avoid bloating your css.


There is a quote in the original answer and my previous answer on the IE8 line that throws this off, right near the semi-colon. Yikes and BAAAAD! The code below has the rotation set correctly and works. You have to float in IE for the filter to be applied.

<div style="
    float: left; 
    position: relative;
    -moz-transform: rotate(270deg);  /* FF3.5+ */        
    -o-transform: rotate(270deg);  /* Opera 10.5 */   
    -webkit-transform: rotate(270deg);  /* Saf3.1+, Chrome */              
    filter:  progid:DXImageTransform.Microsoft.BasicImage(rotation=3);  /* IE6,IE7 */          
    -ms-filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); /* IE8 */           
"
>Count & Value</div>;

Here is one that works for plain-text with some server side processing:

public string RotateHtmltext(string innerHtml)
{
   const string TRANSFORMTEXT = "transform: rotate(90deg);";
   const string EXTRASTYLECSS = "<style type='text/css'>.r90 {"
                                 + "-webkit-" + TRANSFORMTEXT
                                 + "-moz-" + TRANSFORMTEXT
                                 + "-o-" + TRANSFORMTEXT
                                 + "-ms-" + TRANSFORMTEXT
                                 + "" + TRANSFORMTEXT
                                 + "width:1em;line-height:1ex}</style>";
   const string WRAPPERDIV = "<div style='display: table-cell; vertical-align: middle;'>";

   var newinnerHtml = string.Join("</div>"+WRAPPERDIV, Regex.Split(innerHtml, @"<br */?>").Reverse());

   newinnerHtml = Regex.Replace(newinnerHtml, @"((?:<[^>]*>)|(?:[^<]+))",
                                 match => match.Groups[1].Value.StartsWith("<")
                                             ? match.Groups[1].Value
                                             : string.Join("", match.Groups[1].Value.ToCharArray().Select(x=>"<div class='r90'>"+x+"</div>")),
                                 RegexOptions.Singleline);
   return EXTRASTYLECSS + WRAPPERDIV + newinnerHtml + "</div>";
}

which gives something like:

<style type="text/css">.r90 {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
width: 1em;
line-height: 1ex; 
}</style>
<div style="display: table-cell; vertical-align: middle;">
<div class="r90">p</div>
<div class="r90">o</div>
<div class="r90">s</div>
</div><div style="display: table-cell; vertical-align: middle;">
<div class="r90">(</div>
<div class="r90">A</div>
<div class="r90">b</div>
<div class="r90">s</div>
<div class="r90">)</div>
</div>

http://jsfiddle.net/TzzHy/