137

假设我有几列,其中一些我想旋转以下值:

http://jsfiddle.net/MTyFP/1/

<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>

使用这个 CSS:

.statusColumn b {
  writing-mode: tb-rl;
  white-space: nowrap;
  display: inline-block;
  overflow: visible;
  transform: rotate(-90deg);
  transform-origin: 50% 50%;
}

它最终看起来像这样:

一系列四个块级元素。 第三个元素的文本被旋转。

是否可以编写任何 CSS 将导致旋转元素影响其父元素的高度,以便文本不会与其他元素重叠?像这样的东西:

第三列的文本现在会影响其父框的高度,以使文本适合该框。

4

7 回答 7

72

假设你想旋转 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工作的事实。因此,为了创建旋转元素并使其父元素的高度尊重旋转的效果,我们需要做以下事情:

  1. 不知何故构造了一些其他元素,其高度等于.element-to-rotate
  2. 将我们的变换写在上面.element-to-rotate,以便将它准确地覆盖在步骤 1 中的元素上。

步骤 1 中的元素应为.rotation-wrapper-outer. 但是我们怎样才能使它的高度等于宽度.element-to-rotate

我们策略中的关键部分是padding: 50% 0on .rotation-wrapper-inner。这个漏洞是规范的一个古怪细节padding:填充百分比,即使是padding-toppadding-bottom,总是被定义为元素容器宽度的百分比。这使我们能够执行以下两步技巧:

  1. 我们开始display: table.rotation-wrapper-outer。这导致它具有收缩到适合的宽度,这意味着它的宽度将根据其内容的固有宽度设置 - 即,基于 的固有宽度.element-to-rotate。(在支持的浏览器上,我们可以使用 更干净地实现这一点width: max-content,但截至 2017 年 12 月,Edge 仍然不支持max-content。)
  2. 我们将heightof设置.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-rotatehas display: block(以便边距在其上正常工作)然后应用 -50% 来实现这margin-top一点 - 请注意,百分比边距也是相对于父元素的宽度定义的。

就是这样!

为什么这不完全符合规范?

由于规范中百分比填充和边距定义中的以下注释(粗体我的):

百分比是根据生成框的包含块的宽度计算的,即使对于'padding-top''padding-bottom'也是如此。如果包含块的宽度取决于此元素,则结果布局在 CSS 2.1 中未定义。

由于整个技巧围绕着使内部包装元素的填充与其容器的宽度相关,而容器的宽度又取决于其子元素的宽度,所以我们遇到了这种情况并调用了未定义的行为。不过,它目前适用于所有 4 种主要浏览器 - 与我尝试过的一些看似符合规范的调整不同,比如更改.rotation-wrapper-inner为兄弟.element-to-rotate而不是父。

于 2017-12-17T22:21:22.350 回答
68

正如G-Cyr正确指出的那样,目前writing-mode. 结合简单的旋转,您可以获得所需的确切结果。请参见下面的示例。

.statusColumn {
  position: relative;
  border: 1px solid #ccc;
  padding: 2px;
  margin: 2px;
  width: 200px;
}

.statusColumn i,
.statusColumn b,
.statusColumn em,
.statusColumn strong {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
  display: inline-block;
  overflow: visible;
}
<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>

于 2018-05-18T08:23:05.910 回答
42

不幸的是(?)这是它应该如何工作的,即使你旋转你的元素它仍然有一定的宽度和高度,旋转后不会改变。你在视觉上改变它,但是当你旋转东西时没有不可见的包装盒改变它的大小。

想象一下将其旋转小于 90°(例如transform: rotate(45deg)):您将不得不引入这种不可见的盒子,它现在具有基于您正在旋转的对象的原始尺寸和实际旋转值的模糊尺寸。

旋转对象

突然间,你不仅拥有了你旋转过的对象的widthand height,而且还拥有了围绕它的“隐形盒子”的widthand 。height想象一下请求这个对象的外部宽度——它会返回什么?物体的宽度,还是我们的新盒子?我们如何区分两者?

因此,没有可以编写的 CSS 来修复此行为(或者我应该说,“自动化”它)。当然,您可以手动增加父容器的大小,或者编写一些 JavaScript 来处理它。

(为了清楚起见,您可以尝试使用element.getBoundingClientRect来获取前面提到的矩形)。

规范中所述

在 HTML 命名空间中,transform 属性不会影响被转换元素周围的内容流。

这意味着不会对您正在转换的对象周围的内容进行任何更改,除非您手动进行。

转换对象时唯一要考虑的是溢出区域:

(...) 溢出区域的范围考虑了转换后的元素。这种行为类似于元素通过相对定位偏移时发生的情况。

请参阅此 jsfiddle 以了解更多信息。

使用以下方法将这种情况与对象偏移进行比较实际上非常好:position: relative- 即使您正在移动对象(示例),周围的内容也不会改变。


如果您想使用 JavaScript 处理此问题,请查看问题。

于 2013-04-30T14:21:10.033 回答
25

使用百分比padding和伪元素来推送内容。在 JSFiddle 中,我将伪元素保留为红色以显示它,您必须补偿文本的偏移,但我认为这是要走的路。

.statusColumn {
    position: relative;
    border: 1px solid #ccc;
    padding: 2px;
    margin: 2px;
    width: 200px;
}

.statusColumn i, .statusColumn b, .statusColumn em, .statusColumn strong {
  writing-mode: tb-rl;
  white-space: nowrap;
  display: inline-block;
  overflow: visible;
  -webkit-transform: rotate(-90deg);
  -moz-transform: rotate(-90deg);
  -ms-transform: rotate(-90deg);
  -o-transform: rotate(-90deg);
  transform: rotate(-90deg);
  -webkit-transform: rotate(-90deg);

  /* also accepts left, right, top, bottom coordinates; not required, but a good idea for styling */
  -webkit-transform-origin: 50% 50%;
  -moz-transform-origin: 50% 50%;
  -ms-transform-origin: 50% 50%;
  -o-transform-origin: 50% 50%;
  transform-origin: 50% 50%;

  /* Should be unset in IE9+ I think. */
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
}
.statusColumn b:before{ content:''; padding:50% 0; display:block;  background:red; position:relative; top:20px
}
<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>

http://jsfiddle.net/MTyFP/7/

可以在此处找到有关此解决方案的说明:http: //kizu.ru/en/fun/rotated-text/

于 2013-04-30T14:07:49.147 回答
11

请在我的其他答案中查看更新版本。这个答案不再有效,根本不再起作用。由于历史原因,我将把它留在这里。


这个问题已经很老了,但是在当前对.getBoundingClientRect()对象及其widthheight值的支持下,结合使用这种简洁方法的能力transform,我认为我的解决方案也应该被提及。

在这里查看它的实际应用。(在 Chrome 42、FF 33 和 37 中测试。)

getBoundingClientRect计算元素的实际盒子宽度和高度。很简单,然后,我们可以遍历所有元素并将其最小高度设置为他们孩子的实际盒子高度。

$(".statusColumn").each(function() {
    var $this = $(this),
        child = $this.children(":first");
    $this.css("minHeight", function() {
        return child[0].getBoundingClientRect().height;
    });
});

(通过一些修改,您可以遍历孩子并找出哪个是最高的,并将父级的高度设置为最高的孩子。但是,我决定使示例更简单。您还可以将父级的填充添加到如果需要,可以使用高度,或者可以box-sizing在 CSS 中使用相关值。)

但请注意,我在您的 CSS 中添加了一个translateandtransform-origin以使定位更加灵活和准确。

transform: rotate(-90deg) translateX(-100%);
transform-origin: top left;
于 2015-05-13T09:59:50.430 回答
0

支持跨浏览器的好解决方案(Firefox、Chrome、Safari、Edge 和 IE11!):

尝试一下,同时调整浏览器窗口的大小。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width>">
        <title></title>
        <style>
            .container {
                display: flex;
                border: 1px solid grey;
            }

            .vertical,
            .horizontal {
                padding: 8px;
                font-size: 16px;
            }

            .vertical {
                min-width: 20px;
                line-height: 20px;
                writing-mode: tb-rl;
                writing-mode: vertical-rl;
                white-space: nowrap;
                text-align: center;
                transform: rotate(180deg);
            }

            .horizontal {
                border-left: 1px solid grey;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <div class="vertical">
                Lorem ipsum dolor sit amet eiusmod
            </div>
            <div class="horizontal">
                Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
            </div>
        </div>
    </body>
</html>

于 2021-07-15T22:08:12.907 回答
-22

我知道这是一篇旧帖子,但我在解决完全相同的问题时发现了它。对我有用的解决方案是相当粗糙的“低技术”方法,只需将我旋转 90 度的 div 用大量

<br>

知道 div 的大致宽度(旋转后变为高度),我可以通过在该 div 周围添加 br 来补偿差异,以便相应地推动上方和下方的内容。

于 2014-07-16T20:40:17.927 回答