Let's say I have a couple of columns, of which some I'd like to rotate the values of:
<div class="container">
<div class="statusColumn"><span>Normal</span></div>
<div class="statusColumn"><a>Normal</a></div>
<div class="statusColumn"><b>Rotated</b></div>
<div class="statusColumn"><abbr>Normal</abbr></div>
</div>
With this CSS:
.statusColumn b {
writing-mode: tb-rl;
white-space: nowrap;
display: inline-block;
overflow: visible;
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
It ends up looking like this:
Is it possible to write any CSS that will cause the rotated element to affect its parent's height, such that the text would not overlap the other elements? Something like this:
Please see the updated version in my other answer. This answer is no longer valid and simply does not work any more. I'll leave it here for historical reasons.
This question is quite old, but with the current support for the
.getBoundingClientRect()
object and itswidth
andheight
values, in combination with the ability to use this neat method together withtransform
, I think my solution should be mentioned as well.See it in action here. (Tested in Chrome 42, FF 33 & 37.)
getBoundingClientRect
calculates the actual box width and height of the element. Quite simply, then, we can loop through all elements and set its min-height to the actual box height of their children.(With some modification you can loop through the children and find out which one's the tallest and set the height of the parent to the tallest child. However, I decided to make the example more straightforward. You can also add padding of the parent to the height if you want, or you can use a relevant
box-sizing
value in CSS.)Note, though, that I added a
translate
andtransform-origin
to your CSS to make the positioning more flexible and accurate.As the comment by G-Cyr rightfully points out, current support for
writing-mode
is more than decent. Combined with a simple rotate, you get the exact result that you want. See the example below.Unfortunately (?) this is how it's suppose to work even though you rotate your element it still has certain width and height, that does not change after rotation. You visually change it, but there is no invisible wrapping box that changes its size when you rotate things.
Imagine rotating it less than 90° (e.g.
transform: rotate(45deg)
): you would have to introduce such invisible box which now has ambiguous dimensions based on the original dimensions of the object you're rotating and the actual rotation value.Suddenly, you do not only have the
width
andheight
of the object you have rotated, but you also have thewidth
andheight
of the "invisible box" around it. Imagine requesting the outer width of this object - what would it return? The width of the object, or our new box? How would we distinguish between both?Therefore, there is no CSS that you can write to fix this behavior (or should I say, "automate" it). Of course you can increase the size of your parent container by hand, or write some JavaScript to handle that.
(Just to be clear, you can try using
element.getBoundingClientRect
to get the rectangle mentioned before).As described in the spec:
This means that no changes will be made to the content surrounding the object you're transforming, unless you do them by hand.
The only thing that is taken into account when you transform your object is the overflow area:
See this jsfiddle to learn more.
It's actually quite good to compare this situation to an object offset using:
position: relative
- the surrounding content does not change, even though you're moving your object around (example).If you want to handle this using JavaScript, have a look at this question.
Assuming that you want to rotate 90 degrees, this is possible, even for non-text elements - but like many interesting things in CSS, it requires a little cunning. My solution also technically invokes undefined behaviour according to the CSS 2 spec - so while I've tested and confirmed that it works in Chrome, Firefox, Safari, and Edge, I can't promise you that it won't break in a future browser release.
Short answer
Given HTML like this, where you want to rotate
.element-to-rotate
...... introduce two wrapper elements around the element that you want to rotate:
... and then use the following CSS, to rotate anti-clockwise (or see the commented out
transform
for a way to change it into a clockwise rotation):Stack snippet demo
How does this work?
Confusion in the face of the incantations I've used above is reasonable; there's a lot going on, and the overall strategy is not straightforward and requires some knowledge of CSS trivia to understand. Let's go through it step by step.
The core of the problem we face is that transformations applied to an element using its
transform
CSS property all happen after layout has taken place. In other words, usingtransform
on an element does not affect the size or position of its parent or of any other elements, at all. There is absolutely no way to change this fact of howtransform
works. Thus, in order to create the effect of rotating an element and having its parent's height respect the rotation, we need to do the following things:.element-to-rotate
.element-to-rotate
such as to overlay it exactly on the element from step 1.The element from step 1 shall be
.rotation-wrapper-outer
. But how can we cause its height to be equal to.element-to-rotate
's width?The key component in our strategy here is the
padding: 50% 0
on.rotation-wrapper-inner
. This exploit's an eccentric detail of the spec forpadding
: that percentage paddings, even forpadding-top
andpadding-bottom
, are always defined as percentages of the width of the element's container. This enables us to perform the following two-step trick:display: table
on.rotation-wrapper-outer
. This causes it to have shrink-to-fit width, which means that its width will be set based upon the intrinsic width of its contents - that is, based upon the intrinsic width of.element-to-rotate
. (On supporting browsers, we could achieve this more cleanly withwidth: max-content
, but as of December 2017,max-content
is still not supported in Edge.)height
of.rotation-wrapper-inner
to 0, then set its padding to50% 0
(that is, 50% top and 50% bottom). This causes it to take up vertical space equal to 100% of the width of its parent - which, through the trick in step 1, is equal to the width of.element-to-rotate
.Next, all that remains is to perform the actual rotation and positioning of the child element. Naturally,
transform: rotate(-90deg)
does the rotation; we usetransform-origin: top left;
to cause the rotation to happen around the top-left corner of the rotated element, which makes the subsequent translation easier to reason about, since it leaves the rotated element directly above where it would otherwise have been drawn. We can then usetranslate(-100%)
to drag the element downwards by a distance equal to its pre-rotation width.That still doesn't quite get the positioning right, because we still need to offset for the 50% top padding on
.rotation-wrapper-outer
. We achieve that by ensuring that.element-to-rotate
hasdisplay: block
(so that margins will work properly on it) and then applying a -50%margin-top
- note that percentage margins are also defined relative to the width of the parent element.And that's it!
Why isn't this fully spec-compliant?
Because of the following note from the definition of percentage paddings and margins in the spec (bolding mine):
Since the entire trick revolved around making the padding of the inner wrapper element be relative to the width of its container which was in turn dependent upon the width of its child, we're hitting this condition and invoking undefined behaviour. It currently works in all 4 major browsers, though - unlike some seemingly spec-compliant tweaks to approach that I've tried, like changing
.rotation-wrapper-inner
to be a sibling of.element-to-rotate
instead of a parent.Use percentages for
padding
and a pseudo element to push the content. In the JSFiddle I left the pseudo element red to show it and you'll have to compensate the shift of the text but I think that's the way to go.http://jsfiddle.net/MTyFP/7/
A write-up of this solution can be found here: http://kizu.ru/en/fun/rotated-text/
The writing mode property will do this. Current support for
writing-mode
is more than decent. Combined with a simple rotate, you get the exact result that you want. See the example below.(Split from the answer by Bram Vanroy)