flex父母将赢得过去的儿童内容,即使孩子的宽度为0

发布于 2025-02-05 03:16:57 字数 1580 浏览 3 评论 0原文

请考虑以下示例:

.flexer {
  display: inline-flex;
  border: 1px solid red;
  min-width: 0;
}
.extra {
  flex: 0 1 0%; /* flex-grow: 0; flex-shrink: 1; flex-basis: 0%; */
  min-width: 0;
  transition: flex-grow .3s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
}
.flexer:hover .extra {
  flex-grow: 1
}
<div class="flexer">
  <div>
     test
  </div>
  <div class="extra">
    extra
  </div>
</div>

<hr>
<div class="flexer">
  <div>
     test
  </div>
</div> - How it should look, when not hovered
<br>
<div class="flexer">
  <div>
     test
  </div>
  <div>
    extra
  </div>
</div> - How it should look, when hovered
<br><br>
The red box should animate smoothly and precisely between the two widths (without delay).

我很难理解为什么.flexer(父)不悬停时不会收缩(例如:红色框仍然保持满,而不是围绕test test)。

从此 q/a 我理解添加min - 宽:0给孩子应允许父母收缩。我将其添加到孩子和父母,无济于事。

注1:我更感兴趣地了解机制以及为什么会发生这种情况,而不是找到替代解决方案(JavaScript,绝对定位等...)。
我想使用FlexBox,并且想动画Flex -Grow - 或任何其他动画Flex Prop-对于这种情况,如果可能的话。

注2:标记是无关紧要的(我愿意更改它 - 例如:在任何孩子中添加包装器,如果这会使我的示例起作用)。

注意3:有关对所需输出的更清晰的了解,请参见我意识到仅使用CSS不可能的基于JS的答案。

感谢您调查。

Please consider the following example:

.flexer {
  display: inline-flex;
  border: 1px solid red;
  min-width: 0;
}
.extra {
  flex: 0 1 0%; /* flex-grow: 0; flex-shrink: 1; flex-basis: 0%; */
  min-width: 0;
  transition: flex-grow .3s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
}
.flexer:hover .extra {
  flex-grow: 1
}
<div class="flexer">
  <div>
     test
  </div>
  <div class="extra">
    extra
  </div>
</div>

<hr>
<div class="flexer">
  <div>
     test
  </div>
</div> - How it should look, when not hovered
<br>
<div class="flexer">
  <div>
     test
  </div>
  <div>
    extra
  </div>
</div> - How it should look, when hovered
<br><br>
The red box should animate smoothly and precisely between the two widths (without delay).

I have trouble understanding why .flexer (the parent) doesn't shrink when not hovered (e.g: the red box still remains full, instead of shrinking around test).

From this q/a I understand adding min-width: 0 to the child should allow the parent to shrink. I've added it to both child and parent, to no avail.

Note 1: I'm more interested in understanding the mechanics and why this happens than finding an alternative solution (javascript, absolute positioning, etc...).
I'd like to use flexbox and I'd like to animate flex-grow - or any other animatable flex prop - for this case, if at all possible.

Note 2: the markup is irrelevant (I'm open to changing it - e.g: adding a wrapper to any of the children, if that will make my example work).

Note 3: for a clearer understanding of the desired output, see the JS based answer I added after I realised this is not possible using only CSS.

Thanks for looking into this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

还给你自由 2025-02-12 03:16:57

这是我的尝试

.flexer {
  display: inline-flex;
  border: 1px solid red;
  min-width: 0;
}
.extra {
  flex: 0 1 0%; /* flex-grow: 0; flex-shrink: 1; flex-basis: 0%; */
  width: 0;
  transition: flex-grow .3s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
}

.flexer:hover .extra {
  flex-grow: 1;
  width: 100%; /* you can also use 'auto' value */
}
<div class="flexer">
  <div>
     test
  </div>
  <div class="extra">
    extra
  </div>
</div>

Here is my try

.flexer {
  display: inline-flex;
  border: 1px solid red;
  min-width: 0;
}
.extra {
  flex: 0 1 0%; /* flex-grow: 0; flex-shrink: 1; flex-basis: 0%; */
  width: 0;
  transition: flex-grow .3s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
}

.flexer:hover .extra {
  flex-grow: 1;
  width: 100%; /* you can also use 'auto' value */
}
<div class="flexer">
  <div>
     test
  </div>
  <div class="extra">
    extra
  </div>
</div>

反差帅 2025-02-12 03:16:57

您正好在正轨。只需将width:0;添加到.extra并删除min Width。然后将width用于.extra on :Hover fit-contentauto 。

.flexer {
  display: inline-flex;
  border: 1px solid red;
}

.extra {
  flex: 0 1 0%;
  /* flex-grow: 0; flex-shrink: 1; flex-basis: 0%; */
  transition: flex-grow .3s cubic-bezier(.4, 0, .2, 1);
  overflow: hidden;
  width: 0;
}

.flexer:hover .extra {
  flex-grow: 1;
  width: fit-content;
}
<div class="flexer">
  <div>
    test
  </div>
  <div class="extra">
    extra
  </div>
</div>

You were right on track. Just add width: 0; to .extra and remove the min-width. Then set the width for .extra on :hover to fit-content or auto.

.flexer {
  display: inline-flex;
  border: 1px solid red;
}

.extra {
  flex: 0 1 0%;
  /* flex-grow: 0; flex-shrink: 1; flex-basis: 0%; */
  transition: flex-grow .3s cubic-bezier(.4, 0, .2, 1);
  overflow: hidden;
  width: 0;
}

.flexer:hover .extra {
  flex-grow: 1;
  width: fit-content;
}
<div class="flexer">
  <div>
    test
  </div>
  <div class="extra">
    extra
  </div>
</div>

说好的呢 2025-02-12 03:16:57

您将没有任何机会使用flex-Growflex-basis,因为通过设计,这些属性需要知道可行的容器维度。他们无法更新容器尺寸。

您可以做的是使用width/最大宽度,因为这些>可能会影响容器尺寸。

.flexer {
  display: inline-flex;
  border: 1px solid red;
}
.extra {
  min-width: 0;
  max-width: 0;
  transition: .3s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
}
.flexer:hover .extra {
  max-width: 100px;
}
<div class="flexer">
  <div>
     test
  </div>
  <div class="extra">
    extra
  </div>
</div>

或考虑CSS网格,但这在所有浏览器中都无法使用。我认为现在只有Firefox:

.flexer {
  display: inline-grid;
  grid-template-columns: auto 0fr;
  justify-content: start;
  border: 1px solid red;
  transition: .3s cubic-bezier(.4, 0, .2, 1);
}

.extra {
  min-width: 0;
  overflow: hidden;
  width: 100%;
}

.flexer:hover {
  grid-template-columns: auto 1fr;
}
<div class="flexer">
  <div>
    test
  </div>
  <div class="extra">
    extra
  </div>
</div>

You will not have any chance using flex-grow or flex-basis because by design those properties need to know the container dimension to work. they cannot update the container dimension.

What you can do is to play with width/max-width as you already discovered because those can affect the container dimension.

.flexer {
  display: inline-flex;
  border: 1px solid red;
}
.extra {
  min-width: 0;
  max-width: 0;
  transition: .3s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
}
.flexer:hover .extra {
  max-width: 100px;
}
<div class="flexer">
  <div>
     test
  </div>
  <div class="extra">
    extra
  </div>
</div>

Or consider CSS grid but this will not work in all the browsers. Only Firefox for now I think:

.flexer {
  display: inline-grid;
  grid-template-columns: auto 0fr;
  justify-content: start;
  border: 1px solid red;
  transition: .3s cubic-bezier(.4, 0, .2, 1);
}

.extra {
  min-width: 0;
  overflow: hidden;
  width: 100%;
}

.flexer:hover {
  grid-template-columns: auto 1fr;
}
<div class="flexer">
  <div>
    test
  </div>
  <div class="extra">
    extra
  </div>
</div>

煞人兵器 2025-02-12 03:16:57

从到目前为止的所有答案来看,我了解到使用Flexbox的所有孩子的计算宽度时,没有干净的CSS方法可以根据所有儿童的计算宽度来减少父母的大小,而孩子们则在动画时。

从技术上讲,这意味着Flexbox Props(-shrink-basis-grow)无法在此处动画和((最大宽度应该使用。我必须承认,我仍然很难相信。我以为Flexbox涵盖了这个问题。

动画<代码>最大宽度或width的问题是,您无法从0auto> auto没有JavaScript。

导致以下解决方案:

[...document.querySelectorAll('.flexer')].forEach(el => {
  const item = el.querySelector('.extra');
  if (item) {
    el.onmouseenter = () => {
      item.style.maxWidth = item.scrollWidth + 'px'
    }
    el.onmouseleave = () => {
      item.style.maxWidth = '0'
    }
  }
})
.flexer {
  display: inline-flex;
  border: 1px solid red;
}
.extra {
  transition: max-width .42s cubic-bezier(.4, 0, .2, 1);
  overflow: hidden;
  max-width: 0;
  white-space: nowrap;
}
<div class="flexer">
  <div>
    test
  </div>
  <div class="extra">
     extra
  </div>
</div>

<div class="flexer">
  <div>
    test
  </div>
  <div class="extra">
     I have a lot more content...
  </div>
</div>

不用指出的是,如果任何人都有纯CSS解决方案,从0到每个项目的适当宽度完美地动画,我很乐意将其答案标记为接受。

到目前为止,提供的答案都没有所需的输出,除了使用JavaScript的答案。

From all the answers so far, I understand there's no clean CSS way to reduce the size of the parent based on computed widths of all children, while the children are being animated, using flexbox.

Technically, this means flexbox props (-shrink, -basis, -grow) can't be used to animate here and (max-)width should be used instead. I must admit, I still find it hard to believe. I would have thought flexbox got this covered.

The problem with animating max-width or width is you can't animate from 0 to auto without JavaScript.

Which leads to the following solution:

[...document.querySelectorAll('.flexer')].forEach(el => {
  const item = el.querySelector('.extra');
  if (item) {
    el.onmouseenter = () => {
      item.style.maxWidth = item.scrollWidth + 'px'
    }
    el.onmouseleave = () => {
      item.style.maxWidth = '0'
    }
  }
})
.flexer {
  display: inline-flex;
  border: 1px solid red;
}
.extra {
  transition: max-width .42s cubic-bezier(.4, 0, .2, 1);
  overflow: hidden;
  max-width: 0;
  white-space: nowrap;
}
<div class="flexer">
  <div>
    test
  </div>
  <div class="extra">
     extra
  </div>
</div>

<div class="flexer">
  <div>
    test
  </div>
  <div class="extra">
     I have a lot more content...
  </div>
</div>

Needless to point out, if anyone has a pure CSS solution, which animates perfectly from 0 to the appropriate width for each item, I'd be happy to mark their answer as accepted.

So far, none of the provided answers has the desired output, except this one, which uses JavaScript.

似最初 2025-02-12 03:16:57
<div class="flexer">
  <div>
     test
  </div>
  <div class="extra">
    extra
  </div>
</div>
.flexer {
  display: inline-flex;
  border: 1px solid red;
}
.extra {
  flex: 0 1 0%;
  transition: flex-grow .3s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
  width: 0;
}
.flexer:hover .extra {
  flex-grow: 1;
  width: auto;
}

<div class="flexer">
  <div>
     test
  </div>
  <div class="extra">
    extra
  </div>
</div>
.flexer {
  display: inline-flex;
  border: 1px solid red;
}
.extra {
  flex: 0 1 0%;
  transition: flex-grow .3s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
  width: 0;
}
.flexer:hover .extra {
  flex-grow: 1;
  width: auto;
}

https://jsfiddle.net/1kvx2obq/1/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文