Assuming you want to rotate 90 degrees, this is even possible for non-text elements, but, like so many interesting things in CSS, it takes a little trick. My solution also technically causes undefined behavior according to the CSS 2 specification, so while I tested and confirmed that it works in Chrome, Firefox, Safari and Edge, I cannot promise that it will not break in a future browser release.
Short answer
Given such HTML where you want to rotate .element-to-rotate ...
<div id="container"> <something class="element-to-rotate">bla bla bla</something> </div>
... introduce two wrapper elements around the element you want to rotate:
<div id="container"> <div class="rotation-wrapper-outer"> <div class="rotation-wrapper-inner"> <something class="element-to-rotate">bla bla bla</something> </div> </div> </div>
... and then use the following CSS to rotate counterclockwise (or see a missed transform for a way to change it to clockwise rotation):
.rotation-wrapper-outer { display: table; } .rotation-wrapper-inner { padding: 50% 0; height: 0; } .element-to-rotate { display: block; transform-origin: top left; transform: rotate(-90deg) translate(-100%); margin-top: -50%; white-space: nowrap; }
Demo version
p { background: pink; margin: 1px 0; border: 1px solid black; } .rotation-wrapper-outer { display: table; } .rotation-wrapper-inner { padding: 50% 0; height: 0; } .element-to-rotate { display: block; transform-origin: top left; transform: rotate(-90deg) translate(-100%); margin-top: -50%; white-space: nowrap; }
<div id="container"> <p>Some text</p> <p>More text</p> <div class="rotation-wrapper-outer"> <div class="rotation-wrapper-inner"> <p class="element-to-rotate">Some rotated text</p> </div> </div> <p>Even more text</p> <img src="https://i.stack.imgur.com/ih8Fj.png"> <div class="rotation-wrapper-outer"> <div class="rotation-wrapper-inner"> <img class="element-to-rotate" src="https://i.stack.imgur.com/ih8Fj.png"> </div> </div> <img src="https://i.stack.imgur.com/ih8Fj.png"> </div>
How it works?
Confusion in the face of the spells I used above is reasonable; there is a lot going on, and the general strategy is not simple and requires some knowledge of CSS trivia to understand. Skip it step by step.
The core of the problem we are facing is that the transformations applied to an element using its CSS transform property occur after the layout has occurred. In other words, using transform in an element does not affect the size or position of its parent or any other elements. There is absolutely no way to change this fact of how transform works. Thus, to create the effect of rotation of the element and its parent height, observe the rotation, we need to do the following:
- Somehow we are constructing some other element whose height is equal to the width
.element-to-rotate - Write our transform on
.element-to-rotate to superimpose it exactly on the element from step 1.
The element from step 1 should be .rotation-wrapper-outer . But how can we bring its height to .element-to-rotate ?
A key component of our strategy is padding: 50% 0 on .rotation-wrapper-inner . This uses the eccentric detail of the specification for padding : this percentage padding , even for padding-top and padding-bottom , is always defined as the percentage of the width of the element container. This allows us to perform the following two-stage trick:
- We set
display: table to .rotation-wrapper-outer . This leads to the fact that it has a shrinkage width to a width , which means that its width will be set based on the inner width of its contents, that is, based on the inner width. .element-to-rotate . (With browser support, we could achieve this more cleanly with width: max-content , but as of December 2017, max-content still not supported in Edge ). - We set the
height .rotation-wrapper-inner to 0, and then set its padding to 50% 0 (i.e. 50% top and 50% bottom). This forces him to occupy a vertical space equal to 100% of the width of his parent element, which, by the trick in step 1, is equal to the width. .element-to-rotate .
Then it remains only to perform the actual rotation and positioning of the child. Naturally transform: rotate(-90deg) ; we use transform-origin: top left; to make the rotation take place around the upper left corner of the rotated element, which simplifies the subsequent translation as it leaves the rotating element immediately above where it would otherwise be drawn. Then we can use translate(-100%) to drag the element down a distance equal to its width before rotation.
This is still not quite correctly positioned, because we still need to compensate for 50% of the top fill on .rotation-wrapper-outer . We achieve this by ensuring that .element-to-rotate is set to display: block (so that the fields will work correctly on it), and then applying -50% margin-top - note that percentage fields are also defined relative to the width of the parent element.
And this!
Why is this not fully compliant?
Due to the following note from the definition of percentage gaskets and fields in the specification (greasy ground):
The percentage is calculated by the width of the generated block containing the block , even for padding-top and padding-bottom . If the width of this block depends on this element, then the resulting layout is not defined in CSS 2.1.
Since the whole trick revolved around the fact that the addition of the inner wrapper element was related to the width of its container, which, in turn, depended on the width of its child element, we encounter this condition and cause undefined behavior. It currently works in all 4 major browsers, although, unlike some seemingly speculative settings that suit me, such as modifying .rotation-wrapper-inner to be an .element-to-rotate element .element-to-rotate instead of parent.