CSS中的旋转元素会正确影响其父母的身高 [英] Rotated elements in CSS that affect their parent's height correctly

查看:97
本文介绍了CSS中的旋转元素会正确影响其父母的身高的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let's say I have a couple of columns, of which some I'd like to rotate the values of:

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

Is it possible to write any CSS that will cause the rotated element to affect its parent's height, such that the text would not overlap the other elements? Something like this:

推荐答案

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

Assuming that you want to rotate 90 degrees, this is possible, even for non-text elements - but like many interesting things in CSS, it requires a little cunning. My solution also technically invokes undefined behaviour according to the CSS 2 spec - so while I've tested and confirmed that it works in Chrome, Firefox, Safari, and Edge, I can't promise you that it won't break in a future browser release.

给出这样的HTML,您要在其中旋转.element-to-rotate ...

Given HTML like this, where you want to rotate .element-to-rotate...

<div id="container">
  <something class="element-to-rotate">bla bla bla</something>
</div>

...在要旋转的元素周围引入两个包装器元素:

... introduce two wrapper elements around the element that you want to rotate:

<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,将其更改为顺时针旋转):

... and then use the following CSS, to rotate anti-clockwise (or see the commented out transform for a way to change it into a clockwise rotation):

.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琐事知识才能理解.让我们逐步进行一下.

Confusion in the face of the incantations I've used above is reasonable; there's a lot going on, and the overall strategy is not straightforward and requires some knowledge of CSS trivia to understand. Let's go through it step by step.

我们面临的问题的核心是使用

The core of the problem we face is that transformations applied to an element using its transform CSS property all happen after layout has taken place. In other words, using transform on an element does not affect the size or position of its parent or of any other elements, at all. There is absolutely no way to change this fact of how transform works. Thus, in order to create the effect of rotating an element and having its parent's height respect the rotation, we need to do the following things:

  1. 以某种方式构造一些 other 元素,其高度等于.element-to-rotate
  2. 的宽度
  3. .element-to-rotate上编写我们的转换,以便将其准确地覆盖在步骤1的元素上.
  1. Somehow construct some other element whose height is equal to the width of the .element-to-rotate
  2. Write our transform on .element-to-rotate such as to overlay it exactly on the element from step 1.

步骤1中的元素应为.rotation-wrapper-outer.但是我们如何使其 height 等于.element-to-rotate width ?

The element from step 1 shall be .rotation-wrapper-outer. But how can we cause its height to be equal to .element-to-rotate's width?

我们策略中的关键组件是.rotation-wrapper-inner上的padding: 50% 0.此漏洞利用 padding 规范的怪异细节:即使是padding-toppadding-bottom,该百分比填充始终定义为元素容器的宽度的百分比.这使我们能够执行以下两步操作:

The key component in our strategy here is the padding: 50% 0 on .rotation-wrapper-inner. This exploit's an eccentric detail of the spec for padding: that percentage paddings, even for padding-top and padding-bottom, are always defined as percentages of the width of the element's container. This enables us to perform the following two-step trick:

  1. 我们在.rotation-wrapper-outer上设置了display: table.这会导致其具有缩小到适合宽度,这意味着其宽度将根据它的内容-即基于.element-to-rotate的固有宽度. (在支持的浏览器上,我们可以使用width: max-content更加干净地实现此目的,但是截至2017年12月,max-content
  1. We set display: table on .rotation-wrapper-outer. This causes it to have shrink-to-fit width, which means that its width will be set based upon the intrinsic width of its contents - that is, based upon the intrinsic width of .element-to-rotate. (On supporting browsers, we could achieve this more cleanly with width: max-content, but as of December 2017, max-content is still not supported in Edge.)
  2. We set the height of .rotation-wrapper-inner to 0, then set its padding to 50% 0 (that is, 50% top and 50% bottom). This causes it to take up vertical space equal to 100% of the width of its parent - which, through the trick in step 1, is equal to the width of .element-to-rotate.

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

Next, all that remains is to perform the actual rotation and positioning of the child element. Naturally, transform: rotate(-90deg) does the rotation; we use transform-origin: top left; to cause the rotation to happen around the top-left corner of the rotated element, which makes the subsequent translation easier to reason about, since it leaves the rotated element directly above where it would otherwise have been drawn. We can then use translate(-100%) to drag the element downwards by a distance equal to its pre-rotation width.

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

That still doesn't quite get the positioning right, because we still need to offset for the 50% top padding on .rotation-wrapper-outer. We achieve that by ensuring that .element-to-rotate has display: block (so that margins will work properly on it) and then applying a -50% margin-top - note that percentage margins are also defined relative to the width of the parent element.

就是这样!

由于以下注释中的百分比填充和边距定义规范(正在轰炸):

相对于生成的框的width 来计算百分比. rel ="noreferrer">包含阻止,即使对于 'padding-top''padding-bottom' . 如果包含块的宽度取决于此元素,则结果布局在CSS 2.1中未定义.

The percentage is calculated with respect to the width of the generated box's containing block, even for 'padding-top' and 'padding-bottom'. If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1.

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

Since the entire trick revolved around making the padding of the inner wrapper element be relative to the width of its container which was in turn dependent upon the width of its child, we're hitting this condition and invoking undefined behaviour. It currently works in all 4 major browsers, though - unlike some seemingly spec-compliant tweaks to approach that I've tried, like changing .rotation-wrapper-inner to be a sibling of .element-to-rotate instead of a parent.

这篇关于CSS中的旋转元素会正确影响其父母的身高的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆