假设你想旋转 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 琐事知识才能理解。让我们一步一步来。
我们面临的问题的核心是使用其 CSS 属性应用于元素的转换transform
都发生在布局发生之后。换句话说,transform
在元素上使用根本不会影响其父元素或任何其他元素的大小或位置。绝对没有办法改变这个如何transform
工作的事实。因此,为了创建旋转元素并使其父元素的高度尊重旋转的效果,我们需要做以下事情:
- 不知何故构造了一些其他元素,其高度等于
.element-to-rotate
- 将我们的变换写在上面
.element-to-rotate
,以便将它准确地覆盖在步骤 1 中的元素上。
步骤 1 中的元素应为.rotation-wrapper-outer
. 但是我们怎样才能使它的高度等于宽度呢?.element-to-rotate
我们策略中的关键部分是padding: 50% 0
on .rotation-wrapper-inner
。这个漏洞是规范的一个古怪细节padding
:填充百分比,即使是padding-top
和padding-bottom
,总是被定义为元素容器宽度的百分比。这使我们能够执行以下两步技巧:
- 我们开始
display: table
了.rotation-wrapper-outer
。这导致它具有收缩到适合的宽度,这意味着它的宽度将根据其内容的固有宽度设置 - 即,基于 的固有宽度.element-to-rotate
。(在支持的浏览器上,我们可以使用 更干净地实现这一点width: max-content
,但截至 2017 年 12 月,Edge 仍然不支持max-content
。)
- 我们将
height
of设置.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
has display: block
(以便边距在其上正常工作)然后应用 -50% 来实现这margin-top
一点 - 请注意,百分比边距也是相对于父元素的宽度定义的。
就是这样!
为什么这不完全符合规范?
由于规范中百分比填充和边距定义中的以下注释(粗体我的):
百分比是根据生成框的包含块的宽度计算的,即使对于'padding-top'和'padding-bottom'也是如此。如果包含块的宽度取决于此元素,则结果布局在 CSS 2.1 中未定义。
由于整个技巧围绕着使内部包装元素的填充与其容器的宽度相关,而容器的宽度又取决于其子元素的宽度,所以我们遇到了这种情况并调用了未定义的行为。不过,它目前适用于所有 4 种主要浏览器 - 与我尝试过的一些看似符合规范的调整不同,比如更改.rotation-wrapper-inner
为兄弟.element-to-rotate
而不是父。