Angenommen, Sie möchten um 90 Grad drehen, ist dies auch für Nicht-Text-Elemente möglich - aber wie viele interessante Dinge in CSS erfordert es ein wenig List. Meine Lösung ruft auch technisch undefiniertes Verhalten gemäß der CSS 2-Spezifikation auf. Während ich getestet und bestätigt habe, dass es in Chrome, Firefox, Safari und Edge funktioniert, kann ich Ihnen nicht versprechen, dass es in Zukunft nicht mehr funktioniert Browser-Release.
Kurze Antwort
Bei HTML wie diesem, wo Sie drehen möchten .element-to-rotate
...
<div id="container">
<something class="element-to-rotate">bla bla bla</something>
</div>
... führen Sie zwei Wrapper-Elemente um das Element ein, das Sie drehen möchten:
<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>
... und verwenden Sie dann das folgende CSS, um gegen den Uhrzeigersinn zu drehen (oder lesen Sie im Kommentar aus transform
, wie Sie es in eine Drehung im Uhrzeigersinn ändern können):
.rotation-wrapper-outer {
display: table;
}
.rotation-wrapper-inner {
padding: 50% 0;
height: 0;
}
.element-to-rotate {
display: block;
transform-origin: top left;
/* Note: for a CLOCKWISE rotation, use the commented-out
transform instead of this one. */
transform: rotate(-90deg) translate(-100%);
/* transform: rotate(90deg) translate(0, -100%); */
margin-top: -50%;
/* Not vital, but possibly a good idea if the element you're rotating contains
text and you want a single long vertical line of text and the pre-rotation
width of your element is small enough that the text wraps: */
white-space: nowrap;
}
Stack-Snippet-Demo
p {
/* Tweak the visuals of the paragraphs for easier visualiation: */
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;
/* Note: for a CLOCKWISE rotation, use the commented-out
transform instead of this one. */
transform: rotate(-90deg) translate(-100%);
/* transform: rotate(90deg) translate(0, -100%); */
margin-top: -50%;
/* Not vital, but possibly a good idea if the element you're rotating contains
text and you want a single long vertical line of text and the pre-rotation
width of your element is small enough that the text wraps: */
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>
Wie funktioniert das?
Verwirrung angesichts der Beschwörungsformeln, die ich oben verwendet habe, ist vernünftig; Es ist viel los, und die Gesamtstrategie ist nicht einfach und erfordert einige Kenntnisse der CSS-Trivia, um sie zu verstehen. Lassen Sie uns Schritt für Schritt durchgehen.
Der Kern des Gesichts Problem , das wir ist , dass Transformationen auf ein Element angewendet unter Verwendung seiner transform
CSS - Eigenschaft alle geschehen , nachdem das Layout stattgefunden hat. Mit anderen Worten, die Verwendung transform
eines Elements wirkt sich überhaupt nicht auf die Größe oder Position seines übergeordneten Elements oder anderer Elemente aus. Es gibt absolut keine Möglichkeit, diese Tatsache zu ändern, wie es transform
funktioniert. Um den Effekt des Drehens eines Elements zu erzielen und die Höhe seines Elternteils der Drehung zu entsprechen, müssen wir die folgenden Dinge tun:
- Konstruieren Sie irgendwie ein anderes Element, dessen Höhe der Breite des entspricht
.element-to-rotate
- Schreiben Sie unsere Transformation
.element-to-rotate
so auf, dass sie genau aus Schritt 1 auf das Element gelegt wird.
Das Element aus Schritt 1 muss sein .rotation-wrapper-outer
. Aber wie können wir veranlassen , seine Höhe gleich zu sein .element-to-rotate
‚s Breite ?
Die Schlüsselkomponente unserer Strategie ist hier die padding: 50% 0
auf .rotation-wrapper-inner
. Dieser Exploit ist ein exzentrisches Detail der Spezifikation fürpadding
: Diese prozentualen Auffüllungen, auch für padding-top
und padding-bottom
, werden immer als Prozentsätze der Breite des Containers des Elements definiert . Dies ermöglicht es uns, den folgenden zweistufigen Trick auszuführen:
- Wir setzen
display: table
auf .rotation-wrapper-outer
. Dies führt dazu, dass es eine Schrumpfbreite hat , was bedeutet, dass seine Breite basierend auf der intrinsischen Breite seines Inhalts festgelegt wird - dh basierend auf der intrinsischen Breite von .element-to-rotate
. (Bei der Unterstützung von Browsern könnten wir dies sauberer erreichen width: max-content
, aber ab Dezember 2017 max-content
wird dies in Edge immer noch nicht unterstützt .)
- Wir setzen das
height
von .rotation-wrapper-inner
auf 0 und dann das Auffüllen auf 50% 0
( dh 50% oben und 50% unten). Dies führt dazu, dass es einen vertikalen Raum einnimmt, der 100% der Breite seines übergeordneten Elements entspricht - was durch den Trick in Schritt 1 gleich der Breite von ist .element-to-rotate
.
Als nächstes müssen nur noch die eigentliche Drehung und Positionierung des untergeordneten Elements durchgeführt werden. Natürlich transform: rotate(-90deg)
macht die Rotation; Wir verwenden transform-origin: top left;
, um die Drehung um die obere linke Ecke des gedrehten Elements zu veranlassen, wodurch die nachfolgende Übersetzung leichter zu begründen ist, da das gedrehte Element direkt über der Stelle verbleibt, an der es sonst gezeichnet worden wäre. Wir können dann translate(-100%)
das Element um einen Abstand nach unten ziehen, der seiner Vorrotationsbreite entspricht.
Das bringt die Positionierung immer noch nicht ganz richtig, da wir immer noch die 50% ige obere Polsterung ausgleichen müssen .rotation-wrapper-outer
. Dies erreichen wir, indem wir sicherstellen, dass dies der Fall .element-to-rotate
ist display: block
(damit die Ränder ordnungsgemäß funktionieren) und dann einen Wert von -50% anwenden. margin-top
Beachten Sie, dass die prozentualen Ränder auch relativ zur Breite des übergeordneten Elements definiert sind.
Und das ist es!
Warum ist dies nicht vollständig spezifikationskonform?
Aufgrund des folgenden Hinweises aus der Definition der prozentualen Auffüllungen und Ränder in der Spezifikation (fettgedruckte Mine):
Der Prozentsatz wird in Bezug auf die Breite des Blocks der generierten Box berechnet , selbst für "Auffüllen oben" und "Auffüllen unten" . Wenn die Breite des enthaltenen Blocks von diesem Element abhängt, ist das resultierende Layout in CSS 2.1 nicht definiert.
Da sich der gesamte Trick darum drehte, das Auffüllen des inneren Wrapper-Elements relativ zur Breite seines Containers zu machen, was wiederum von der Breite seines untergeordneten Elements abhängt, treffen wir diese Bedingung und rufen undefiniertes Verhalten auf. Derzeit funktioniert es jedoch in allen vier gängigen Browsern - im Gegensatz zu einigen scheinbar spezifikationskonformen Änderungen .rotation-wrapper-inner
, die ich versucht habe, wie zum Beispiel ein Geschwister .element-to-rotate
anstelle eines Elternteils zu werden.