小编典典

CSS中正确影响父级高度的旋转元素

css

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

<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%;
}

阅读 435

收藏
2020-05-16

共1个答案

小编典典

假设您希望旋转90度,即使对于非文本元素也可以旋转-但是像CSS中许多有趣的事情一样,它需要一些技巧。根据CSS 2规范,我的解决方案还会从技术上调用未定义的行为-因此,尽管我已经测试并确认它可以在Chrome,Firefox,Safari和Edge中使用,但我不能保证将来不会损坏浏览器版本。

Short answer

给定这样的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琐事知识才能理解。让我们逐步进行。

我们面临的问题的核心是,使用其transformCSS属性对元素进行的转换都是在布局发生后进行的。换句话说,transform在元素上使用完全不影响其父元素或任何其他元素的大小或位置。绝对没有办法改变这种transform工作方式。因此,为了产生旋转元素并使其父代的高度尊重旋转的效果,我们需要执行以下操作:

以某种方式构造其他元素的高度等于元素的宽度.element-to-rotate
编写我们的转换,.element-to-rotate以便将其准确地覆盖在步骤1的元素上。
步骤1中的元素应为.rotation-wrapper-outer。但是,如何使它的高度等于.element-to-rotate的宽度呢?

我们策略中的关键部分是padding: 50% 0on .rotation-wrapper-inner。此漏洞利用是该规范的怪异细节padding:即使对于padding-top和padding-bottom,填充百分比也总是定义为元素容器宽度的百分比。这使我们能够执行以下两步技巧:

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

就是这样!

为什么不完全符合规范?
由于以下规范中的填充百分比和边距定义(注释矿井),请注意以下几点:

即使对于’padding-top’和’padding-bottom’而言,百分比也是相对于所生成的盒子的包含块的宽度来计算的。如果包含块的宽度取决于此元素,则结果布局在CSS 2.1中未定义。

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

2020-05-16