Flexbox child 具有 "overflow: hidden" 溢出的祖父母边距

Flexbox child with "overflow: hidden" overflowing grandparent margins

我正在尝试将两个 child 元素嵌套在指定边距的包装器中,因此当显示较窄且 max-width 用于宽屏显示。

第二个 child 有一些应该可见的溢出,而第一个 child 应该严格保持在包装器的内容框中。删除第一个 child 后,第二个 child 将按预期运行。但是,当我添加第一个 child 时,它似乎完全忽略了包装器的边距,拉伸了包装器的内容框并破坏了第二个 child。

overflow: hidden 应用到包装器修复了边距问题,但剪掉了第二个 child。将边距应用到第一个 child 并没有使它与 parent 一起折叠,因为它在一个新的块格式上下文中。

到目前为止我发现的唯一解决方法是:

.wrapper {
    > * {
        margin-left: 1.5rem;
        margin-right: 1.5rem;
    }
}

并将包装器的 max-width 增加 3rem 但我希望有一些解决方案不需要我将边距从包装器转移到它的 children.

https://codepen.io/HybridCore/pen/jjoWmd

body {
  background-color: #000;
  color: #FFF;
  display: flex;
  justify-content: center;
}

.wrapper {
  margin: 0 1.5rem;
  max-width: 40rem;
  width: 100%;
}

.fit_content_box {
  display: flex;
  align-items: center;
}

.L {
  min-width: 0;
  flex: 1 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.R {
  margin-left: 1rem;
  height: 1rem;
  width: 1rem;
  background-color: #FFF;
}

.overflow {
  display: flex;
  justify-content: space-between;
}

.overflow>div {
  width: 0;
  display: flex;
  justify-content: center;
}
<body>
  <div class="wrapper">
    <div class="fit_content_box">
      <p class="L">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 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.</p>

      <div class="R"></div>
    </div>

    <div class="overflow">
      <div>
        <p>0</p>
      </div>
      <div>
        <p>12</p>
      </div>
      <div>
        <p>24</p>
      </div>
    </div>
  </div>
</body>

问题的根源似乎是 white-space: nowrap,它应用于第一个子项 (.fit_content_box) 内的内容元素 (.L)。

.L {
    border: solid 1px #FF0000;
    min-width: 0;
    flex: 1 0;
    overflow: hidden;
    white-space: nowrap;    <--- trouble maker
    text-overflow: ellipsis;
}

如果删除该行代码,.wrapper 上的侧边距将按预期工作。

所以关键问题是:

  • 为什么 grand-child (.L) 上的 white-space 属性 会折叠 grand-parent (.wrapper) 的边距?
  • 为什么 white-space 属性 将侧边距应用到父级 (.fit_content_box) 时折叠?
  • 为什么 overflow 属性 应用到 grand-parent (.wrapper) 时,其值不是 visible,允许边距坚持 grand-child (.L)?

您写道:

Applying the margins to the first child didn't make it collapse with the parent since it's in a new block formatting context.

实际上,这不是常规边距崩溃的问题,因为:

  1. 我们说的是水平边距,还有horizontal margins never collapse,还有

  2. 我们在弹性容器内工作,.

因此,尽管对问题的全面理解可能在于块(或 flex)格式化上下文,但我不确定这就是父级边距不折叠的原因。

这是我对这个问题的了解。当我有时间时,我会做更多的研究。或者其他人可以从这里获取它。

你主要有两个问题:

  1. 您将 width:100% 设置为包装器,这不考虑边距,因此您在逻辑上会溢出,并且由于正文是具有 justify-content:center 的弹性容器,边距将从双方这就是为什么你认为它不适用。
  2. 你面对的是 which is forcing you to set width:100% thinking it's the good solution. This same constraint is also preventing the element from shrinking lower than the 100% you specified (related: )

要解决此问题,您需要从包装器中删除 width:100% 并考虑使用 min-width:0。您还可以删除应用于 .Lmin-width 并且您需要考虑 flex-shrink:0 on .R (或将其宽度替换为 min-width

body {
  background-color: #000;
  color: #FFF;
  display: flex;
  justify-content: center;
}

.wrapper {
  margin: 0 1.5rem;
  max-width: 40rem;
  min-width:0;
}

.fit_content_box {
  display: flex;
  align-items: center;
}

.L {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.R {
  margin-left: 1rem;
  flex-shrink:0;
  height: 1rem;
  width: 1rem;
  background-color: #FFF;
}

.overflow {
  display: flex;
  justify-content: space-between;
}

.overflow>div {
  width: 0;
  display: flex;
  justify-content: center;
}
<body>
  <div class="wrapper">
    <div class="fit_content_box">
      <p class="L">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 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.</p>

      <div class="R"></div>
    </div>

    <div class="overflow">
      <div>
        <p>0</p>
      </div>
      <div>
        <p>12</p>
      </div>
      <div>
        <p>24</p>
      </div>
    </div>
  </div>
</body>

如果您希望元素在有少量文本时至少保持等于 max-width 添加 flex-grow:1:

body {
  background-color: #000;
  color: #FFF;
  display: flex;
  justify-content: center;
}

.wrapper {
  margin: 0 1.5rem;
  max-width: 40rem;
  min-width:0;
  flex-grow:1;
}

.fit_content_box {
  display: flex;
  align-items: center;
}

.L {
  flex-grow:1;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.R {
  margin-left: 1rem;
  flex-shrink:0;
  height: 1rem;
  width: 1rem;
  background-color: #FFF;
}

.overflow {
  display: flex;
  justify-content: space-between;
}

.overflow>div {
  width: 0;
  display: flex;
  justify-content: center;
}
<body>
  <div class="wrapper">
    <div class="fit_content_box">
      <p class="L">Lorem ipsum dolor sit e dolor sit e</p>

      <div class="R"></div>
    </div>

    <div class="overflow">
      <div>
        <p>0</p>
      </div>
      <div>
        <p>12</p>
      </div>
      <div>
        <p>24</p>
      </div>
    </div>
  </div>
</body>


为了更好地说明 (1),这里是另一个您几乎不会注意到的边距溢出的示例:

.container {
  width:200px;
  margin:auto;
  display:flex;
  justify-content:center;
}
.box {
  height:50px;
  width:100%;
  background:red;
}
<div class="container">
  <div class="box" style="margin:0 5966px">a_long_text_to_avoid_the_shrink</div>
</div>

<div class="container">
  <div class="box">a_long_text_to_avoid_the_shrink</div>
</div>

您可以看到我们有一个长文本迫使我们的元素不收缩(min-width 约束),元素占据全宽并且我们将内容居中。这将使边距像没有边距一样溢出。

如果你违反了一条规则,那么你就会看到边距的影响。

删除长文本:

.container {
  width:200px;
  margin:auto;
  display:flex;
  justify-content:center;
}
.box {
  width:100%;
  height:50px;
  background:red;
}
<div class="container">
  <div class="box" style="margin:0 5966px">a long text to avoid the shrink</div>
</div>

<div class="container">
  <div class="box">a long text to avoid the shrink</div>
</div>

删除居中:

.container {
  width:200px;
  margin:auto;
  display:flex;
}
.box {
  width:100%;
  height:50px;
  background:red;
}
<div class="container">
  <div class="box" style="margin:0 5966px">a_long_text_to_avoid_the_shrink</div>
</div>

<div class="container">
  <div class="box">a_long_text_to_avoid_the_shrink</div>
</div>

每边做不同的边距

.container {
  width:200px;
  margin:auto;
  display:flex;
  justify-content:center;
}
.box {
  width:100%;
  height:50px;
  background:red;
}
<div class="container">
  <div class="box" style="margin:0 500px 0 400px">a_long_text_to_avoid_the_shrink</div>
</div>

<div class="container">
  <div class="box">a_long_text_to_avoid_the_shrink</div>
</div>


(2) white-space 正在创建 min-width 约束以防止元素收缩。

举个例子来说明:

.body {
  display: flex;
  justify-content: center;
  margin: 10px 100px;
  border: 2px solid red;
}

.wrapper {
  border: 1px solid;
  margin: 0 20px;
}
.box {
 display:flex;
}
The below is a logical behavior where the text will wrap and the margin are respected
<div class="body">
  <div class="wrapper">
    <div class="box">
      <div>some long text here some long text here some long text here some long text here</div>
    </div>
  </div>
</div>
Let's add white-space:nowrap. We add a min-width contraint since we said to the text to never wrap thus our flex element will not shrink and overflow.
<div class="body">
  <div class="wrapper">
    <div class="box">
      <div style="white-space:nowrap">some long text here some long text here some long text here some long text here</div>
    </div>
  </div>
</div>
If we add width:100% we force its width to be the same as the container BUT the margin aren't included and are kept outside (the text will logically overflow)
<div class="body">
  <div class="wrapper" style="width:100%">
    <div class="box">
      <div style="white-space:nowrap">some long text here some long text here some long text here some long text here</div>
    </div>
  </div>
</div>
Now if we add min-width:0 we remove the constaint of minimum sizing and we can see the margin again even if we keep width:100% because the element will shrink by default
<div class="body">
  <div class="wrapper" style="width:100%;min-width:0">
    <div class="box">
      <div style="white-space:nowrap">some long text here some long text here some long text here some long text here</div>
    </div>
  </div>
</div>

诀窍是我们将元素居中并在两侧应用相同的边距,这会产生边距折叠的错觉,但它只是两侧边距的简单溢出。

让我们稍微改变一侧的边距,看看另一侧有一点偏移:

.body {
  display: flex;
  justify-content: center;
  margin: 10px 100px;
  border: 2px solid red;
}

.wrapper {
  border: 1px solid;
  margin: 0 20px 0 40px;
}
.box {
 display:flex;
}
The below is a logical behavior where the text will wrap and the margin are respected
<div class="body">
  <div class="wrapper">
    <div class="box">
      <div>some long text here some long text here some long text here some long text here</div>
    </div>
  </div>
</div>
Let's add white-space:nowrap. We add a min-width contraint since we said to the text to never wrap thus our flex element will not shrink and overflow.
<div class="body">
  <div class="wrapper">
    <div class="box">
      <div style="white-space:nowrap">some long text here some long text here some long text here some long text here</div>
    </div>
  </div>
</div>
If we add width:100% we force its width to be the same as the container BUT the margin aren't included and are kept outside (the text will logically overflow)
<div class="body">
  <div class="wrapper" style="width:100%">
    <div class="box">
      <div style="white-space:nowrap">some long text here some long text here some long text here some long text here</div>
    </div>
  </div>
</div>
Now if we add min-width:0 we remove the constaint of minimum sizing and we can see the margin again even if we keep width:100% because the element will shrink by default
<div class="body">
  <div class="wrapper" style="width:100%;min-width:0">
    <div class="box">
      <div style="white-space:nowrap">some long text here some long text here some long text here some long text here</div>
    </div>
  </div>
</div>