css - CSS中的旋转元素会正确影响其 parent 的高度

标签 css css-transforms

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

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来使旋转后的元素影响其父级的高度,从而使文本不会与其他元素重叠?像这样:

最佳答案

假设您想旋转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="/image/ih8Fj.png">
  <div class="rotation-wrapper-outer">
    <div class="rotation-wrapper-inner">
      <img class="element-to-rotate" src="/image/ih8Fj.png">
    </div>
  </div>
  <img src="/image/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。该漏洞利用的an eccentric detail of the spec for padding:即使对于padding-toppadding-bottom,填充百分比也总是定义为元素容器宽度的百分比。这使我们能够执行以下两步技巧:


我们在display: table上设置.rotation-wrapper-outer。这导致它具有shrink-to-fit width,这意味着将根据其内容的固有宽度(即基于.element-to-rotate的固有宽度)设置其宽度。 (在支持的浏览器上,我们可以使用width: max-content更干净地实现此目的,但是截至2017年12月,max-contentstill not supported in Edge。)
我们将height.rotation-wrapper-inner设置为0,然后将其填充设置为50% 0(即50%顶部和50%底部)。这导致它占用等于其父级宽度的100%的垂直空间-通过步骤1中的技巧,该空间等于.element-to-rotate的宽度。


接下来,剩下的就是执行子元素的实际旋转和定位。自然,transform: rotate(-90deg)进行旋转;我们使用transform-origin: top left;导致旋转围绕旋转元素的左上角发生,这使得随后的平移更容易推论,因为它将旋转元素留在原本应绘制的位置上方。然后,我们可以使用translate(-100%)将元素向下拖动等于其预旋转宽度的距离。

这仍然不能完全正确地定位,因为我们仍然需要补偿.rotation-wrapper-outer上50%的顶部填充。我们通过确保.element-to-rotate具有display: block(以便在其上边距正常工作),然后应用-50%margin-top来实现这一点-请注意,还相对于父元素的宽度定义了边距百分比。

就是这样!

为什么不完全符合规范?

由于the following note from the definition of percentage paddings and margins in the spec(在我的脑海中):


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


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

关于css - CSS中的旋转元素会正确影响其 parent 的高度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54971749/

相关文章:

css - 新字体大小不合适

php - CSS/PHP/MySQL - 将结果显示为 3 列

css - 不同的背景渐变

javascript - SVG:如何为整个图像着色

javascript - 在 CSS "scale"中更改 "transform"属性

javascript - 切换而不是悬停函数 jQuery

html - 如何制作具有挤压效果的3D元素?

css - 将背景图像放在菱形容器中会导致容器变形

html - 将两个旋转的 div 正确嵌入并定位在矩形的 Angular 上?

html - CSS 中的变换比例/旋转效果不应影响 child