CSS 溢出的奇怪效果在 parent 元素的位置隐藏与可见

Strange effect of CSS overflow hidden vs. visible on position of parent element

我从未读过任何内容表明元素的溢出 属性 会对我在此处看到的元素定位产生奇怪的影响:

https://codepen.io/kshetline/pen/ZEzLVxN

切换示例中的切换按钮,观察 <div> 的背景如何神秘地向上滑动,覆盖之前的内容,而其内容保持在相同的 screen-relative 位置(意思是相对于其 parent 的背景,内容正在向下移动。

这个例子是我试图用一个 Angular 组件做的事情的一个非常简化的版本,它意味着扩展它的 <ng-content> — 但这个例子只是 CSS 和HTML 略微 JavaScript,没有 Angular,因为我试图隔离相关变量。

HTML 元素的 内容 可以使用 transform: scale( less-than-1 比例因子 ),但即使元素的内容被渲染得更小,默认情况下元素的像素尺寸保持不变,内容(除非另有说明)向元素的中心收缩,并且空白space 将元素保留在其原始未缩放尺寸的内容周围..

您需要计算与缩放程度相匹配的负边距,以便将元素本身视为更小。我已经这样做了,但我发现除非缩放元素的容器将 CSS overflow 设置为 hidden,否则可能会出现一些奇怪的定位,就好像额外的空白 space 应该被负边距删除的 required 仍然有一些部分,hard-to-explain 对其他元素的整体布局有影响。

我在 Chrome、Firefox、Safari 和 Edge 中看到了这种行为——所以我猜这是 "proper" CSS 的行为,但这对我来说毫无意义,我希望有人可以解释发生了什么。我希望能够将 overflow 设置为 visible,以便缩放后的内容仍然可以执行一些操作,例如显示不会在元素边界处被剪裁的浮动下拉菜单。

let hidden = true;
const inner = document.getElementById('inner')

function toggleOverflow() {
  hidden = !hidden;
  inner.style.overflow = hidden ? 'hidden' : 
  'visible'
}
html, body {
  height: calc(100vh - 10em);
}

.page {
  font: 32px Arial, Helvetica, sans-serif;
  height: calc(100% - 1em);
}

.container {
  background-color: #ACF;
  height: 100%;
}

.outer-wrapper {
  background-color: rgba(187, 255, 204, 0.5);
  font-size: 2em;
  margin: 0 1em;
  position: relative;
}

.inner-wrapper {
  overflow: hidden;
  position: relative;
  width: fit-content;
}

.ng-content {
  margin: -18.75px 0;
  transform: scale(0.5);
}

.container-text {
  display: inline-block;
  position: absolute;
  bottom: 1em;
}
<div class="page">
  <button onclick="toggleOverflow()">Toggle Overflow</button><br>
  Content outside of the<br>
  panel being scaled and its<br>
  containing &lt;div&gt;, 32pt font<br>
  <div class="container">
    <!--Angular component start tag goes here -->
    <div class="outer-wrapper">
      <div id="inner" class="inner-wrapper">
        <div class="ng-content">
          50% scaled content goes here, 64pt font
        </div>
      </div>
    </div>
    <!-- Angular component end tag goes here -->
    <span class="container-text">This is an absolutely positioned &lt;span&gt; in the same &lt;div&gt;</span>
  </div>
</div>

您在 .ng-content 中设置了负边距。如果 overflow 设置为 hidden,它将隐藏负边距。将边距设置为正数,就可以解决这个跳跃问题。

.ng-content { margin: 18.75px 0; }

如果您尝试上下更改元素的高度,请尝试使用 max-heightoverflow: hidden。当最大高度设置为 0 时,它将被隐藏。当设置为 500 像素时,您的内容将会显示!

跟进...

我在这里为我的第一个代码笔创建了一个变体:

https://codepen.io/kshetline/pen/WNeRmOo

在这种情况下,我在缩放时使用 transform-origin: top center,并将所有需要的负边距放在缩放元素的底部,而不是在顶部和底部之间平均分割。这消除了奇怪的垂直位置偏移。

overflow: hidden 仍然需要从其容器的 "leaking out" 隐藏多余的背景颜色,但在缩放元素的背景是透明的(常见)情况下,会有使用 overflow: visible 没有明显的效果,并且不用担心缩放元素内部产生的下拉菜单被剪裁。

后续 #2...

这是最好的解决方案,使用 padding: 0.05px 来处理 @Alochi 帮助我理解的真正问题 — 停止边框折叠:

https://codepen.io/kshetline/pen/zYONgzV

来自CSS 2.2 spec

Margins of elements that establish new block formatting contexts (such as floats and elements with 'overflow' other than 'visible') do not collapse with their in-flow children.

所以添加 overflow:hidden 是为了防止边距折叠。