Якщо припустити, що ви хочете повернути на 90 градусів, це можливо навіть для нетекстових елементів - але, як і багато цікавих речей у CSS, це вимагає трохи хитрості. Моє рішення також технічно посилається на невизначене поведінку відповідно до специфікації CSS 2 - тому, поки я перевіряв і підтверджував, що він працює в Chrome, Firefox, Safari та Edge, я не можу пообіцяти вам, що він не порушиться в майбутньому реліз браузера.
Коротка відповідь
Враховуючи такий HTML, де потрібно обертатись .element-to-rotate
...
<div id="container">
<something class="element-to-rotate">bla bla bla</something>
</div>
... введіть два елемента обгортки навколо елемента, який потрібно обертати:
<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>
... а потім скористайтеся наступним CSS, щоб обертати проти годинникової стрілки (або побачити коментований transform
спосіб змінити його в обертання за годинниковою стрілкою):
.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;
}
Демонстраційний фрагмент стека
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>
Як це працює?
Плутанина перед закликами, які я використав вище, є розумною; багато чого відбувається, і загальна стратегія не є однозначною і вимагає певних знань про дрібниці CSS, щоб зрозуміти. Пройдемося покроково.
Основною проблемою, з якою ми стикаємося, є те, що перетворення, застосовані до елемента, використовуючи його transform
властивість CSS, відбуваються після того, як відбулася компонування. Іншими словами, використання transform
елемента не впливає на розмір чи положення його батьківського чи будь-якого іншого елемента. Існує абсолютно ніякий спосіб змінити цей факт того, як transform
працює. Таким чином, для того, щоб створити ефект обертання елемента і мати висоту його батьків щодо повороту, нам потрібно зробити наступні дії:
- Якось побудуйте якийсь інший елемент, висота якого дорівнює ширині
.element-to-rotate
- Напишіть наше перетворення
.element-to-rotate
таким чином, щоб накласти його точно на елемент із кроку 1.
Елемент кроку 1 повинен бути .rotation-wrapper-outer
. Але як ми можемо змусити його висоту дорівнювати ширині.element-to-rotate
' ?
Ключовим компонентом нашої стратегії тут є padding: 50% 0
включення .rotation-wrapper-inner
. Цей експлуатувальний ексцентричний опис специфікації дляpadding
: цей відсоток прокладок, навіть для padding-top
і padding-bottom
завжди визначається як відсотки від ширини контейнера елемента . Це дає нам змогу виконати наступний двоетапний трюк:
- Ми ставимо
display: table
на .rotation-wrapper-outer
. Це призводить до того, що вона має ширину , що відповідає розміру , що означає, що її ширина буде встановлена на основі внутрішньої ширини її вмісту - тобто на основі внутрішньої ширини .element-to-rotate
. (На підтримку браузерів, ми могли б домогтися цього більш чисто з width: max-content
, але за станом на грудень 2017 року, max-content
це ще не підтримуються в краї .)
- Ми встановили
height
на .rotation-wrapper-inner
0, а потім встановити його заповнення до 50% 0
(тобто, 50% верх і низ 50%). Це призводить до того, що він займає вертикальний простір, що дорівнює 100% ширини його батьківського рівня, що за допомогою фокусу на кроці 1 дорівнює ширині .element-to-rotate
.
Далі, все, що залишається, - це виконати власне обертання та позиціонування дочірнього елемента. Природно, transform: rotate(-90deg)
чи відбувається обертання; ми використовуємо transform-origin: top left;
для того, щоб обертання відбулося в лівому верхньому куті обертового елемента, що полегшує міркування щодо подальшого перекладу, оскільки він залишає повернутий елемент прямо вгорі там, де він інакше був би проведений. Потім ми можемо translate(-100%)
перетягнути елемент вниз на відстань, рівну його ширині перед обертанням.
Це все ще не цілком відповідає правильному позиціонуванню, тому що нам все одно потрібно компенсувати 50% верхньої підкладки .rotation-wrapper-outer
. Ми досягаємо цього, гарантуючи, що .element-to-rotate
має display: block
(так що поля будуть працювати належним чином на ньому), а потім застосовуючи -50% margin-top
- зауважте, що відсоткові поля також визначаються відносно ширини батьківського елемента.
І це все!
Чому це не повністю відповідає специфікаціям?
Через наступне зауваження з визначення відсотків прокладки та запасів у специфікації (напівжирна шахта):
Відсоток обчислюється відносно ширини згенерованого блоку, що містить блок , навіть для 'padding-top' та 'padding-bottom' . Якщо ширина містить блоку залежить від цього елемента, то отриманий макет не визначений у CSS 2.1.
Оскільки вся хитрість оберталася навколо того, щоб набивання внутрішнього елемента обгортки було відносно ширини його контейнера, що в свою чергу залежало від ширини його дочірньої частини, ми вражаємо цю умову і посилаємось на невизначене поведінку. Наразі він працює у всіх чотирьох основних браузерах, однак - на відміну від деяких, здавалося б, специфічних налаштувань наближення до того, що я намагався, як, наприклад, змінити, .rotation-wrapper-inner
щоб бути рідним братом, .element-to-rotate
а не батьком.