'height: fit-content' 没有 CSS 过渡效果。

29

我使用 transition: height 500ms 为元素添加动画效果,该元素通过按钮从 height: 0 滑动到 height: 100px,反之亦然。

由于元素的内容是动态添加的,我不知道它的大小,因此我想改用 height: fit-content。这样,元素将始终具有显示其内容所需的正确大小。

不幸的是,这会禁用动画效果。

如何在 div 元素的大小适合其内容的情况下获得动画效果?

以下代码段显示了行为:

document.querySelector('button')
  .addEventListener(
    'click',
    () => document.querySelectorAll('div')
      .forEach(div => div.classList.toggle('closed')));
div {
  background-color: lightblue;
  border: 1px solid black;
  overflow: hidden;
  transition: height 500ms;
}

div.closed {
  height: 0 !important;
}

div.div1 {
  height: 100px;
}

div.div2 {
  height: fit-content;
}
<button type="button">toggle</button>

<h1>'height: 100px' => 'height: 0'</h1>
<div class="div1">
some text<br />
even more text<br />
so much text
</div>

<br>

<h1>'height: fit-content' => 'height: 0'</h1>
<div class="div2">
some text<br />
even more text<br />
so much text
</div>


fit-content 实际上是一个函数,据我所知它不是可动画化的值。 - TylerH
没有优雅的纯CSS解决方案,jQuery可以轻松解决(.slideToggle())。 - VXp
8个回答

11

正如Mishel所说,另一种解决方案是使用max-height。这是该解决方案的一个可行示例。

关键是在完全展开时近似您的max-height,然后过渡将更加平滑。

希望这能帮到您。

https://www.w3schools.com/css/css3_transitions.asp

document.querySelector('button')
  .addEventListener(
    'click',
    () => document.querySelectorAll('div')
      .forEach(div => div.classList.toggle('closed')));
div {
  background-color: lightblue;
  border: 1px solid black;
  overflow-y: hidden;
 max-height: 75px; /* approximate max height */
 transition-property: all;
 transition-duration: .5s;
 transition-timing-function: cubic-bezier(1, 1, 1, 1);
}
div.closed {
   max-height: 0;
}
<button type="button">toggle</button>

<h1>'height: 100px' => 'height: 0'</h1>
<div class="div1">
some text<br />
even more text<br />
so much text
</div>

<br>

<h1>'height: fit-content' => 'height: 0'</h1>
<div class="div2">
some text<br />
even more text<br />
so much text
</div>


谢谢!这个解决方案最适合我的情况和目标。 - Sebastian Barth
1
作为改进,我使用max-height: 100vh;100vh表示可用视图高度的100%(浏览器窗口的实际内容区域大小)。我的元素始终比100vh小得多。 - Sebastian Barth
很高兴听到这个好消息,我很高兴能够帮助。 - Roskow

5

虽然不太完美,但一种可能的解决方案是对 height 进行动画处理,而不是对其进行调整。

另一种解决方案可能是对 max-height 进行动画处理,而不是对 height 进行调整。您可以使用 max-height,例如 300px 或 500px。但如果需要更多的话,效果就不会很好。

在这里,我正在动画处理字体大小。

希望这有所帮助。谢谢。

document.querySelector('button')
  .addEventListener(
    'click',
    () => document.querySelectorAll('div')
      .forEach(div => div.classList.toggle('closed')));
div {
  background-color: lightblue;
  border: 1px solid black;
  overflow: hidden;
  transition: font-size 500ms;
}

div.closed {
  font-size: 0 !important;
}

div.div1 {
  font-size: 14px;
}

div.div2 {
  font-size: 14px;
}
<button type="button">toggle</button>

<h1>'height: 100px' => 'height: 0'</h1>
<div class="div1">
some text<br />
even more text<br />
so much text
</div>

<br>

<h1>'height: fit-content' => 'height: 0'</h1>
<div class="div2">
some text<br />
even more text<br />
so much text
</div>


我确实在另一种情况下使用了这种方法,其中内容本身就是元素:由于您正在缩放文本元素,因此我也缩放了子元素。感谢提醒! - Sebastian Barth
对于我不同高度的下拉菜单完美地工作。谢谢! - Zhiyong

2
考虑到移动版和桌面版网站的高度差别可能很大,我不喜欢使用max-height解决方案来过渡高度从0到适合内容,因为如果我低估了,它会截断内容,如果我高估了,转换看起来就很奇怪。
这是我的CSS + JS解决方案:
//CSS
div {
    overflow: hidden;
    transition: all 220ms;
}    

div:not(.active) {
    height: 0px !important;
}


//JS
div.addEventListener('click', function(e) {
   div.style.height = `${div.scrollHeight}px`;            
   div.classList.add('active');
});

绝对是最容易在任何语言和框架中拼凑在一起的。 - undefined

0
我制作了一个解决方案,混合使用了`filter`和`transform`属性,实现了一个漂亮的效果。

    .dropdown-content {
        width: fit-content;
        transform: scaleY(0);
        filter: brightness(1000%);
        transform-origin: top;
        transition: all 0.5s;
    }
    .dropdown-content.visible {
        transform: scaleY(1);
        filter: none;
    }

这消除了scaleY()带来的收缩效果。类名为"visible"的元素应通过JavaScript进行切换


0

我使用这个:

function slide(button, event) {
            document.getElementById("container").classList.toggle("container-opened");
        }
.container {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    height: 0;
    overflow: hidden;
    transition: 1s all;
}

.card {
    margin: 10px 5%;
    padding: 10px;
    background-color: #CCC;
}

.container-opened {
    height: 150vh;
    box-shadow: 1px 1px 10px 1px #CCC;
}
<button onclick="slide(this, event)">Slide!!</button>
    <div id="container" class="container">
        <article class="card">
            <p>I'm a children!!</p>
        </article>

        <article class="card">
            <p>I'm a children!!</p>
        </article>

        <article class="card">
            <p>I'm a children!!</p>
        </article>

        <article class="card">
            <p>I'm a children!!</p>
        </article>
    </div>

只需确保高度大于内容本身所占空间,内容就会自动分配。 这也可以与flex-direction: row一起使用,通过操作宽度而不是高度,只需对justify-content和align-items进行微小的更改即可。


0
我解决问题的方法是计算子元素的高度

document.querySelector('.button1').addEventListener('click',
  () => document.querySelector('.div1').classList.toggle('closed'));

document.querySelector('.button2').addEventListener('click',
  () => document.querySelector('.div2').classList.toggle('closed'));

let extendedHeight = 0;
let div2 = document.querySelector('.div2')
for (let i = 0; i < div2.children.length; i++) {
  extendedHeight += div2.children[i].offsetHeight;
}

div2.style.setProperty('--extended-height', extendedHeight.toString() + "px")
div {
  background-color: lightblue;
  border: 1px solid black;
  overflow: hidden;
  transition: 500ms;
}

div.div1.closed {
  max-height: 0 !important;
}

div.div1 {
  max-height: 1000px;
}

div.div2.closed {
  height: 0 !important;
}

div.div2 {
  --extended-height: 0px;
  height: var(--extended-height);
}
<button type="button" class="button1">toggle</button>

<h1>'height: over predicted' => 'height: 0'</h1>
<div class="div1">
  <p>
  some text <br> even more text <br> so much text <br><br>
  </p>
</div>

<button type="button" class="button2">toggle</button>

<h1>'height: calculated' => 'height: 0'</h1>
<div class="div2">
  <p>some text <br> even more text <br> so much text <br><br>
  </p>
</div>

如果高度被过度预测,动画将会看起来破裂,但如果高度被完美计算并设置,动画将能正确地工作并且看起来完美。
为了做到这一点,我使用offsetHeight计算了div的所有子元素的高度,该属性返回元素的高度 + padding-top + border-top + margin-top 然后我将自定义CSS变量--extended-height设置为所有子元素的高度
如果div有不同的元素相互位置,则可能会出现问题。我解决的方法是只获取定位在一起的元素中最大的元素的offsetHeight。在我的情况下,我只使用了其他每个元素的offsetHeight 谢谢

0

你可以尝试使用 tranform: scaleY(0) -> scale(1),它与 height 做的事情有点类似。


0
使用其他人所说的最大高度,但只需将max-height设置为fit-content,它应该按预期工作。

使用百分比而不是像素来表示高度。 - dirtbowl
高度:0% 最大高度:适应内容 悬停{ 高度:100% - dirtbowl
1
你的回答可以通过提供更多支持性信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人能够确认你的回答是否正确。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接