Vertically rotate text inside an HTML table header cell - css

I am using the following css to rotate the text inside table header cells but the header cells is of the same width as if the text were horizontal.How can I just rotate the text and the width will reduce automatically..
table#MyTable tr th a{
color: #FFFFFF;
display: block;
/*Firefox*/
-moz-transform: rotate(-90deg);
/*Safari*/
-webkit-transform: rotate(-90deg);
/*Opera*/
-o-transform: rotate(-90deg);
/*IE*/
writing-mode: tb-rl;
filter: flipv fliph;
padding: 60px 1px;
}

If you need to adjust just the width of the cells and they contain only one line of text each you can do this: http://jsfiddle.net/sSP8W/3/ — set width of an element to it's line-height.
The problem with CSS3-transforms is that they work like as CSS' position: relative: their original box stays the same, so rotating, skewing etc. don't cause the changes in the element's dimensions. So: there is really no perfect CSS solution, you can use JS to adjust the dimensions, or try to find hackety workarounds. So if you have only links in a table, you can do something like that: http://jsfiddle.net/sSP8W/4/ — rotating the table itself.
If your case have another content that you don't want to rotate — update the post, so we could try to find a better solution.
upd: Just found out a solution to the rotated text in tables: using some magic with vertical paddings we could make cells stretch to the content, so look at this almost final example: http://dabblet.com/gist/4072362

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 a year late!

In IE and Chrome (Blink and Webkit), you can put the text in a child with a vertical writing mode rather than using a transform. Saves you all the CSS and JavaScript tricks. Chrome has a minor display bug at the moment (Chrome 37), but it's been reported.
.vertical {
-webkit-writing-mode:vertical-rl;
-ms-writing-mode:tb-rl;
writing-mode:vertical-rl;
}
<td><span class="vertical">This text should be vertical.</span></td>
I recommend using white-space:nowrap on the vertical text within the table.

The solution by jobjorn above now breaks in Chrome, because it supports writing-mode as of early 2016, so essentially tries to rotate the text twice, and ends up with mispositioned horizontal text. From my understanding, Firefox and Safari will probably support this soon too, which will cause them to break too. After some banging my head against the wall, I fixed it by changing the CSS to:
#supports not (writing-mode:vertical-rl) {
table div.rotated {
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
white-space: nowrap;
}
}
#supports (writing-mode:vertical-rl) {
table div.rotated {
writing-mode:vertical-rl;
-webkit-transform: rotate(180deg) translate(8px,0px);
-moz-transform: rotate(180deg) translate(8px,0px);
white-space: nowrap;
}
}
The 8 pixel translation was what it took for the alignment to look right in my particular example. You mileage may vary. The 180 degree rotation was to make the top of the text face left instead of right. If you don't need that, you can probably skip the transforms in the second part.
In the JavaScript, you also need to make sure that you don't move the origin for those last transforms, as that was only needed if you were using a transform to do the vertical orientation itself, so I wrapped that part in a conditional:
var supportsWM = CSS.supports('writing-mode', 'vertical-rl');
if (!supportsWM) {
newInnerDiv.css('-webkit-transform-origin', (width / 2) + 'px ' + (width / 2) + 'px');
newInnerDiv.css('-moz-transform-origin', (width / 2) + 'px ' + (width / 2) + 'px');
}

Mods: sorry that this post "responds to an answer". But I don't have the karma necessary to comment on it. Catch-22.
The code in #jobjorn's answer and fiddl depends on cell width to calculate header height, which leads to erroneous heights when any cell is wide. This modified fiddle uses the header text width instead: http://jsfiddle.net/marvmartian/76z82/
cellsToRotate.each(function () {
var cell = $(this);
var s = '<div id="killme" style="position:absolute; top:-10000px; left:-10000px;"><span id="string_span" style="font-weight: bold; font-size: 1em">'+
cell.text()+'</span></div>';
$(window).append(s);
var width = $('#string_span').width();
var newText = cell.text()
, height = cell.height()
//, width = cell.width()
, newDiv = $('<div>', { height: width, width: height })
, newInnerDiv = $('<div>', { text: newText, 'class': 'rotated' });

Get rid of padding:60px 1px; (unless you need it for some other reason...but that's what's causing the problem).
Example: http://jsfiddle.net/purmou/sSP8W/

This is now possible without any browser specific transforms used in the other answers. Note that the wrapping span is required as of 2022 in order to get firefox in particular to center the rotated text within the column (webkit does this by default).
<style type="text/css">
#myTable td {
text-align: right;
}
th.r span {
transform: rotate(185deg);
writing-mode: vertical-lr;
}
</style>
<table id="myTable" border="1" cellpadding="2" style="border-collapse:collapse;">
<tr>
<th class='r'><span>Display</span></th>
<th class='r'><span>Year made (TV?)</span></th>
<th class='r'><span>Native Res</span></th>
</tr>
<tr>
<td style="color:rgb(17, 85, 204);">Dell U2410 (game) </td>
<td>2010</td>
<td>1080p</td>
</tr>
<tr>
<td style="color:rgb(17, 85, 204);">Dell U2410 (sRGB)</td>
<td>2010</td>
<td>1080p</td>
</tr>
<tr>
<td style="color:rgb(17, 85, 204);"> Sony 40VL130 (game)</td>
<td style="color:rgb(0, 0, 255);">2008</td>
<td>1080p</td>
</tr>
</table>

<style type="text/css">
#myTable td {
text-align: right;
}
th.r span {
transform: rotate(185deg);
writing-mode: vertical-lr;
}
</style>
<table id="myTable" border="1" cellpadding="2" style="border-collapse:collapse;">
<tr>
<th class='r'><span>Display</span></th>
<th class='r'><span>Year made (TV?)</span></th>
<th class='r'><span>Native Res</span></th>
</tr>
<tr>
<td style="color:rgb(17, 85, 204);">Dell U2410 (game) </td>
<td>2010</td>
<td>1080p</td>
</tr>
<tr>
<td style="color:rgb(17, 85, 204);">Dell U2410 (sRGB)</td>
<td>2010</td>
<td>1080p</td>
</tr>
<tr>
<td style="color:rgb(17, 85, 204);"> Sony 40VL130 (game)</td>
<td style="color:rgb(0, 0, 255);">2008</td>
<td>1080p</td>
</tr>
</table>

Related

Set precedence in text wrapping on different characters in CSS

I'd like to display the path of a file in a column of a table, e.g.
some_random_folder/my_long_filename.txt
such that when I need to wrap it, it will first wrap at slashes, then at underscores, e.g. showing the column width with "|":
|some_random_folder/ |
|my_long_filename.txt |
instead of
|some_random_folder/my_long_ |
|filename.txt |
Of course, if the column is too narrow, it still wraps at underscores:
|some_random_ |
|folder/ |
|my_long_ |
|filename.txt |
This is fine too:
|some_random_ |
|folder/my_long_ |
|filename.txt |
I know that I can add <wbr/> to suggest places to wrap, but that seems to have just one level of priority.
Is that possible with pure CSS? (It's fine if IE/Edge is unsupported.)
This can't be done purely in css, so I would suggest using a javascript function for this.
Here is an example using the special html entity ​ to do a line break that will cut the text if needed. If the line break is not needed it will not create a visible whitespace.
This is just a basic example that adds line break after the first "/"-character, you can extend it with all the other logic you might need adding more line breaks if you want:
var spans = document.getElementsByClassName("cutme");
for (var i = 0; i < spans.length; i++) {
var span = spans[i];
var index = span.innerText.indexOf("/");
var text = span.innerText;
span.innerHTML = text.substring(0, index + 1) + "​" + text.substring(index + 1);
}
table {
width: 200px;
}
td {
border-bottom: solid 2px black;
}
<table>
<tbody>
<tr>
<td class="cutme">
some_random_folder/my_long_filename.txt
</td>
</tr>
<tr>
<td class="cutme">
folder/filename.txt
</td>
</tr>
<tr>
<td class="cutme">
some_random_folder/my_long_filename.txt
</td>
</tr>
</tbody>
</table>
If the length of the "some_random_folder/" part is known, #media all and max-width can be hacked to wrap white-space (added after underscores as <wbr />) below a certain window width. 10em works on my browser in the example below. (It even wraps at character level when the width is under 7em.) I change the colour to show when it starts wrapping.
.wrap { white-space:nowrap; font-family:monospace; }
#media all and (max-width:10em) {
.wrap { white-space:normal; color:blue; }
}
#media all and (max-width:7em) {
.wrap { word-break:break-all; word-wrap:break-word; color:red; }
}
<span class="wrap">some_<wbr />random_<wbr />folder/</span><wbr /><span class="wrap">my_<wbr />long_<wbr />filename.txt</span>

Bootstrap Same Height on Table Alert Divs?

had some trouble researching this, maybe I'm just not thinking clearly. I am using Bootstrap 3 and have a table to pull in data and I am highlighting certain data with their Alert styled divs.
The problem I have is that depending on the data they all have differing heights and I want them to all be the same. I've seen other examples but they weren't utilizing a table structure.
Is there a way to do this or is my only option to ditch the tables and do individual bootstrap columns?
Attached is an example of a table row.
I've updated your fiddle. I'm assuming that you have alerts throughout each of your rows, therefore we're iterating through each <tr> and finding the .alert divs, then determining which alert has the most "height". Then we add this height CSS to every .alert in the row.
The HTML structure has changed, I've added <thead> and <tbody>
<table class="table">
<thead>
<tr>
<th>Address</th>
<th>Super Permits</th>
<th>Active?</th>
</tr>
</thead>
<tbody>
....
....
$('.table').find('tbody tr').each(function (e) {
var heights = $(".alert").map(function ()
{
return $(this).outerHeight();
}).get(),
maxHeight = Math.max.apply(null, heights);
$(this).find('.alert').css('height', maxHeight);
});
Just add custom css for the "alert" class, and it will apply to all alert types, like:
.alert {
height: 90px
}
https://jsfiddle.net/W3AVE/4j72mfeo/
HTML
<table>
<tr class='same-height'>
<td><div><span>text</span></div></td>
<td><div><span>some long text here</span></div></td>
<td><div><span>text medium</span></div></td>
</tr>
</table>
CSS
div {
border: 1px solid black;
}
span {
text-align: center;
display: block;
position: relative;
top: 50%;
transform: translate(0, -50%)
}
JS
(function($){
var $el = $(".same-height"),
h = $el.height();
$el.find("div").each(function()
{
var $self = $(this);
$self.css({"height": h});
});
}(jQuery));

min-width isn't preferred strongly enough when child is a table

My previous question got an answer using min-width to set the width of a containing block but allow it to grow when its children are too big.
This worked fine with some kinds of children (simple divs with their own min-width and max-width specified explicitly). Now I'm looking at a more complex variation in which the children are tables. (Legitimate tables with semantically meaningful rows and columns, not page-layout tables.)
There is no manually-specified min-width or max-width on these tables, but tables have an inherent maximum and minimum width, corresponding to the width that the table would have if rendered with no line breaks in any of the cells (maximum) and the width that it would have with line breaks inserted insertion of all possible line breaks (minimum).
In the existing page layout which I'm trying to replace, the outermost container is a table (the bad kind of table) with a single cell in a single row, and a CSS width (not min-width) set to the preferred width. When the children are tables, they try really hard to fit into the container's width. A wide table will be rendered with line breaks to make it fit, and the container will expand only if the child still doesn't fit after all line breaks are inserted.
In other words, the parent's width property is treated as a minimum, but it is also a strongly preferred width, which has a higher priority than the child's preferred (i.e. maximum) width.
By contrast, when the parent is a plain div with display:inline-block and a specified min-width, the parent's min-width is not strongly preferred. The child prefers to be wider, so the parent expands, even if the child is capable of being rendered with a smaller width.
Here's a snippet, much like the one in the previous question, which demonstrates all of this. The goal is to make the second container act like the first one in some way that is more "proper" than using display:table for layout.
(Note: the table widths at the heart of this question are very sensitive to choice of font. I hope the Courier New comes through and everybody sees the same widths in the snippet.)
var containers = document.querySelectorAll(".container");
for(var i = 0; i < containers.length; ++i) {
(function() {
var c = containers[i],
b = c.nextElementSibling;
b.addEventListener("click", function(ev) {
big = c.querySelector(".bigchild");
medium = c.querySelector(".mediumchild");
small = c.querySelector(".smallchild");
if(big.style.display != "block" &&
medium.style.display != "block" &&
small.style.display != "block") {
big.style.display = "block";
} else if(big.style.display == "block") {
big.style.display = "none";
medium.style.display = "block";
} else if(medium.style.display == "block") {
medium.style.display = "none";
small.style.display = "block";
} else {
small.style.display = "none";
}
});
})();
}
body {
background-color: #ccc;
text-align: center;
font-size: 14px;
font-family: "Courier New";
}
table {
border-collapse: collapse;
}
td {
border: 1px solid black;
padding: 5px;
}
.container {
background-color: white;
min-height: 250px;
margin-left: auto;
margin-right: auto;
}
.bigchild, .mediumchild, .smallchild {
display: none;
}
button {
display: block;
margin: 10px auto 20px;
}
#container1 {
display: table;
width: 400px;
}
#container2 {
display: inline-block;
min-width: 400px;
}
<div class="container" id="container1">
<table class="bigchild">
<tr>
<td>Lots of</td>
<td>columns</td>
<td>make this</td>
<td>a very</td>
<td>wide</td>
<td>table</td>
<td>that won't</td>
<td>fit</td>
<td>even with</td>
<td>added</td>
<td>line breaks</td>
</tr>
</table>
<table class="mediumchild">
<tr>
<td>This table</td>
<td>is smaller</td>
<td>and</td>
<td>it fits</td>
<td>but</td>
<td>only with</td>
<td>added</td>
<td>line breaks</td>
</tr>
</table>
<table class="smallchild">
<tr>
<td>very</td>
<td>small</td>
</tr>
</table>
</div>
<button>Next</button>
<div class="container" id="container2">
<table class="bigchild">
<tr>
<td>Lots of</td>
<td>columns</td>
<td>make this</td>
<td>a very</td>
<td>wide</td>
<td>table</td>
<td>that won't</td>
<td>fit</td>
<td>even with</td>
<td>added</td>
<td>line breaks</td>
</tr>
</table>
<table class="mediumchild">
<tr>
<td>This table</td>
<td>is smaller</td>
<td>and</td>
<td>it fits</td>
<td>but</td>
<td>only with</td>
<td>added</td>
<td>line breaks</td>
</tr>
</table>
<table class="smallchild">
<tr>
<td>very</td>
<td>small</td>
</tr>
</table>
</div>
<button>Next</button>
I think .container {min-width: 400px;width: min-content;}, modulo vendor prefixes, is what you want.

CSS text justify with letter spacing

Is there a way to automatically justify words using letter spacing, each in its row, to a defined width, using CSS?
For example, "Something like this" would look, well, something like this:
Is there a non-obtrusive way to apply such styling to my text? I believe pure CSS doesn't have this option (at least not with CSS versions before 3, CSS3 seems to have a text-justify property, but it's not well supported yet), so js solutions would be fine also.
Here's a script which can do it. It isn't pretty, but maybe you can hack it to meet your needs. (Updated to handle resizing)
function SplitText(node) {
var text = node.nodeValue.replace(/^\s*|\s(?=\s)|\s*$/g, "");
for (var i = 0; i < text.length; i++) {
var letter = document.createElement("span");
letter.style.display = "inline-block";
letter.style.position = "absolute";
letter.appendChild(document.createTextNode(text.charAt(i)));
node.parentNode.insertBefore(letter, node);
var positionRatio = i / (text.length - 1);
var textWidth = letter.clientWidth;
var indent = 100 * positionRatio;
var offset = -textWidth * positionRatio;
letter.style.left = indent + "%";
letter.style.marginLeft = offset + "px";
//console.log("Letter ", text[i], ", Index ", i, ", Width ", textWidth, ", Indent ", indent, ", Offset ", offset);
}
node.parentNode.removeChild(node);
}
function Justify() {
var TEXT_NODE = 3;
var elem = document.getElementById("character_justify");
elem = elem.firstChild;
while (elem) {
var nextElem = elem.nextSibling;
if (elem.nodeType == TEXT_NODE)
SplitText(elem);
elem = nextElem;
}
}
#character_justify {
position: relative;
width: 40%;
border: 1px solid red;
font-size: 32pt;
margin: 0;
padding: 0;
}
#character_justify * {
margin: 0;
padding: 0;
border: none;
}
<body onload="Justify()">
<p id="character_justify">
Something<br/> Like
<br/> This
</p>
</body>
The css only solution is text-justify: distribute https://www.w3.org/TR/css-text-3/#text-justify but the support is still very poor.
A small experiment using text-align-last: justify and adding spaces between letters.
div{
display:inline-block;
text-align: justify;
text-align-last: justify;
letter-spacing: -0.1em;
}
<div>
S o m e t h i n g<br>
l i k e<br>
t h i s
</div>
I know this is an old topic, but I faced this the other night. And found a suitable solution using tables.
Every letter shall be put into a <td> </td> I know it looks tedious, but if you wanna do this, it would be for a word or two, right? Or you always can use JS to fill it if is too much. However, this is only CSS and very versatile solution.
Using letter-spacing the letters get distributed properly. You should play around with it, depending on the width of the table.
#justify {
width: 300px;
letter-spacing: 0.5em;
}
<table id="justify">
<tbody>
<tr>
<td>J</td>
<td>U</td>
<td>S</td>
<td>T</td>
<td>I</td>
<td>F</td>
<td>Y</td>
</tr>
</tbody>
</table>
See the example here
Crossbrowser safe, virtually nothing shall differ. Is just CSS.
I used it in My website which is in english and spanish.
the subtitle under my name in spanish has an additional letter and it will step out the width. Using the tables explained above, it gets distributed to the same width automatically. Spacing it manually I'd had to define a whole condition for each language to go around that.
Here is an other aproach using a jQuery snippet I wrote for this question : Stretch text to fit width of div :
DEMO
HTML :
<div class="stretch">Something</div>
<div class="stretch">Like</div>
<div class="stretch">This</div>
jQuery :
$.fn.strech_text = function () {
var elmt = $(this),
cont_width = elmt.width(),
txt = elmt.html(),
one_line = $('<span class="stretch_it">' + txt + '</span>'),
nb_char = elmt.text().length,
spacing = cont_width / nb_char,
txt_width;
elmt.html(one_line);
txt_width = one_line.width();
if (txt_width < cont_width) {
var char_width = txt_width / nb_char,
ltr_spacing = spacing - char_width + (spacing - char_width) / nb_char;
one_line.css({
'letter-spacing': ltr_spacing
});
} else {
one_line.contents().unwrap();
elmt.addClass('justify');
}
};
$(document).ready(function () {
$('.stretch').each(function () {
$(this).strech_text();
});
});
Needed this too, so I've bundled the suggested technique in a simple to use jquery-plugin you can find here: https://github.com/marc-portier/jquery-letterjustify#readme.
It uses the same procedure at its core, and adds some options to tweak.
Comments welcome.
Found another way to achieve this with pure CSS, alas you need to spell out your words.
In my situation, this was the only solution that worked (some letters had classes), plus it also produced the straightest right-alignment among answers here, without using hacks.
.box {
width: min-content;
border: solid red;
}
.word {
display: flex;
justify-content: space-between;
}
<div class="box">
<div class="word">
<span>S</span>
<span>o</span>
<span>m</span>
<span>e</span>
<span>t</span>
<span>h</span>
<span>i</span>
<span>n</span>
<span>g</span>
<span> </span>
<span>w</span>
<span>i</span>
<span>c</span>
<span>k</span>
<span>e</span>
<span>d</span>
</div>
<div class="word">
<span>t</span>
<span>h</span>
<span>i</span>
<span>s</span>
<span> </span>
<span>w</span>
<span>a</span>
<span>y</span>
</div>
<div class="word">
<span>c</span>
<span>o</span>
<span>m</span>
<span>e</span>
<span>s</span>
</div>
</div>
Again, I know this is REALLY old, but why not just put a space between each letter and then text-align:justify? Then each letter would be regarded as a 'word' and justified accordingly
An alternate way to handle this might be to use the "vw" sizing unit. This unit type can be used in font size properties and represents a percent of the window's width.
Disclaimer: It is not exactly what you are looking for, but requires no scripting. It does adjust the text size, but will also scale to the width of your page.
For example,
.heading {
font-size: 4vw;
}
will make the width of one character in the current font 4% of the window width.
You could then use media queries if you wish to lock the font size to a minimum size based on the window's width.
#media only screen and (max-width: 768px) {
font-size: 2rem;
}
Use the browser inspector to play with the font-size property and tweak the value to what makes sense for your application.
The "vw" unit works in IE9+, iOS 8.3+ and Android 4.4+ and all other mainstream browsers. I wouldn't worry about the mobile support too much, as you can use media queries to put the right sizing for these devices as described above.
http://caniuse.com/#feat=viewport-units
https://css-tricks.com/viewport-sized-typography/
Viewport units are a powerful way to scale many different aspects of your site with little code.
I just made a JQuery script from table's Tony B approach.
Here is the JSFiddle https://jsfiddle.net/7tvuzkg3/7/
This script creates a table with each char in a row. This works with full sentence.
I'm not sure this is fully optimized.
justifyLetterSpacing("sentence");
function justifyLetterSpacing(divId) {
// target element
domWrapper = $('#' + divId).clone().html('');
// construct <td>
$('#' + divId).contents().each(function(index){
// store div id to td child elements class
var tdClass = divId ;
// split text
$textArray = $(this).text().split('');
// insert each letters in a <td>
for (var i = 0; i < $textArray.length; i++) {
// if it's a 'space', replace him by an 'html space'
if( $textArray[i] == " " ) {
$('<td>')
.addClass(tdClass)
.html(" ")
.appendTo(domWrapper);
}// if it's a char, add it
else{
$('<td>')
.addClass(tdClass)
.text($textArray[i])
.appendTo(domWrapper);
}
}
});
// create table
table =
$( "<table id='"+divId+"'/>" ).append(
$( "<tbody>" ).append(
$( "<tr>" ).append(
( domWrapper ).children('td')
)
)
);
// replace original div
$('#' + divId).replaceWith( table );
}
#sentence {
width : 100%;
background-color : #000;
color : #fff;
padding : 1rem;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="sentence">LOREM IPSUM DOLOR</div>
I usually try to write my answer on time. and this is exactly the same time (after 10 years) =)
myText.innerHTML = myText.textContent
.split(/\s+/g)
.map((line) => line.trim().split("").join(" "))
.join("<br>");
#myText {
display: inline-block;
text-align: justify;
text-align-last: justify;
letter-spacing: -0.125em;
font-family: sans-serif;
}
<div id="myText">Something like this</div>

Rotating table header text with CSS transforms

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!
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?
‘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.
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> </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.
Webkit has added:
-webkit-writing-mode:vertical-rl;
Which you can apply to a div.
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!
In order to have rotated text inside your table headers:
Place the header content inside divs - rotate these divs rather than the header itself
Set the position:relative on the table headers th, position:absolute on the rotated divs.
Set height of th headers too
Done.
You can see it 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;
}
This tool did all the thinking for me...
http://www.boogdesign.com/examples/transforms/matrix-calculator.html

Resources