ChatGPT解决这个技术问题 Extra ChatGPT

我怎样才能过渡高度:0;到高度:自动;使用 CSS?

我正在尝试使用 CSS 过渡制作 <ul> 向下滑动。

<ul>height: 0; 开始。悬停时,高度设置为 height:auto;。然而,这导致它只是出现,不是过渡,

如果我从height: 40px;height: auto;,那么它会滑到height: 0;,然后突然跳到正确的高度。

如果不使用 JavaScript,我还能如何做到这一点?

#child0 { 高度:0;溢出:隐藏;背景颜色:#dedede; -moz-transition:高度 1s 轻松; -webkit-transition: height 1s ease; -o-transition:高度 1s 轻松;过渡:高度 1s 缓和; } #parent0:hover #child0 { height: auto; } #child40 { 高度:40px;溢出:隐藏;背景颜色:#dedede; -moz-transition:高度 1s 轻松; -webkit-transition: height 1s ease; -o-transition:高度 1s 轻松;过渡:高度 1s 缓和; } #parent40:hover #child40 { height: auto; } h1 { 字体粗细:粗体;两个 CSS 片段之间的唯一区别是一个高度:0,另一个高度:40。


Hover me (height: 0)

部分内容
部分内容
部分内容
部分内容
部分内容
部分内容

悬停在我身上(高度:40)

部分内容
部分内容
部分内容
部分内容
部分内容< br>部分内容

我相信 height:auto/max-height 解决方案只有在您扩展的区域大于您想要限制的 height 时才有效。如果你有一个 300pxmax-height,但有一个组合框下拉菜单,它可以返回 50px,那么 max-height 对你没有帮助,50px 是可变的,取决于元素的数量,你可以到达到一个不可能的情况,因为 height 未修复,我无法修复它,height:auto 是解决方案,但我不能使用转换。
OP 正在尝试 css 解决方案,而不是 js,否则他们只能使用溢出和动画
@VIDesignz:但内部 div 的 -100% margin-top 接收包装 div 的宽度,而不是高度。所以这个解决方案与最大高度解决方案有同样的问题。此外,当宽度小于内容的高度时,并非所有内容都被 -100% margin-top 隐藏。所以这是一个错误的解决方案。
有关正确解决方案的规范和实施的讨论,请参见 github.com/w3c/csswg-drafts/issues/626
@Paulie_D 问题是关于高度,而不是宽度。所有的答案都是关于身高的。请不要将问题标题更改为与它无关的内容。

j
jlouzado

在转换中使用 max-height 而不是 height。并将 max-height 上的值设置为比您的框所能获得的更大的值。

请参阅 Chris Jordan 在此处的另一个 answer 中提供的JSFiddle demo

#menu #list { 最大高度:0;过渡:最大高度 0.15s 缓出;溢出:隐藏;背景:#d5d5d5; } #menu:hover #list { 最大高度:500px;过渡:最大高度 0.25s 缓入; }


这很好用!除了启动时有延迟,因为它启动的最大高度最初非常高..hmm,我认为这有点烦人
+1 很好的解决方案!转换的速度计算为您指定转换到最大高度值的时间......但由于高度将小于最大高度,转换到实际高度的速度将比指定的时间。
请注意,当您必须使用比实际计算值大得多的值时,这可能会导致难看的过渡结束。我在尝试使 div 从 0 高度增长到由于屏幕尺寸不同而变化很大的内容高度时注意到了这一点(我的 2560x1440 显示器上的 2 行与智能手机上的 >10 行)。为此,我最终选择了 js。
非常丑陋的解决方案,因为它会在一个方向上产生延迟,但不会在另一个方向上产生延迟。
这是一个非常懒惰的解决方案。我假设 OP 想要使用 height : auto 因为容器的扩展高度有些不可预测。此解决方案将导致动画可见之前的延迟。此外,动画的可见持续时间将是不可预测的。通过计算每个容器子节点的组合高度,然后缓和到精确的高度值,您将获得更可预测(并且可能更平滑)的结果。
d
dotnetCarpenter

您应该改用 scaleY 。

ul { 背景颜色:#eee;变换:scaleY(0);变换原点:顶部;过渡:变换 0.26s 缓动; } p:hover ~ ul { 变换: scaleY(1); }

Hover This

  • 咖啡
  • 牛奶

我在 jsfiddle 上制作了上述代码的供应商前缀版本,并将您的 jsfiddle 更改为使用 scaleY 而不是 height。

编辑 有些人不喜欢 scaleY 转换内容的方式。如果这是一个问题,那么我建议改用 clip

ul {剪辑:矩形(自动,自动,0,自动);位置:绝对;边距:-1rem 0;填充:0.5rem;白颜色;背景颜色:rgba(0, 0, 0, 0.8);过渡属性:剪辑;过渡持续时间:0.5s;过渡时间函数:三次贝塞尔曲线(0.175、0.885、0.32、1.275); } h3:hover ~ ul, h3:active ~ ul, ul:hover { clip: rect(auto, auto, 10rem, auto); }

悬停在这里

  • 这个列表
  • 被剪辑。
  • 剪辑过渡
  • 将显示它
  • li>

一些文字...


这种方法只是部分地达到了预期的效果,但实际上并没有删除空间。转换后的盒子就像一个相对定位的元素 - 无论它如何缩放,都会占用空间。查看 this jsFiddle,它采用了您的第一个,只是在底部添加了一些虚假文本。请注意,当框高度缩放为零时,它下面的文本不会向上移动。
现在可以了:jsfiddle.net/gNDX3/1 基本上,您需要根据需要设置元素的样式。 CSS/HTML 中没有灵丹妙药或类似小部件的行为。
虽然我为尝试不同方法的人鼓掌,但这个解决方案带来的现实效果和复杂性远比已经可怕的最大高度黑客要糟糕得多。请不要使用。
“现在可以了”,只是消失的元素下方的内容在元素滑开之前跳了起来。有时可能很有用,但是过渡的重点是平滑地改变视觉效果,而不是用一个明显的跳跃换另一个。
实际上,使用 clip 转换与简单地设置 max-height 值没有什么不同。它仍然受到高度动态内容大小的不固定数量的动画延迟的影响。
a
animuson

当涉及的高度之一是 auto 时,您当前无法在高度上设置动画,您必须设置两个明确的高度。


S
Samuel Liew

我一直使用的解决方案是先淡出,然后缩小 font-sizepaddingmargin 值。它看起来与擦除不同,但它可以在没有静态 heightmax-height 的情况下工作。

工作示例:

/* 最终显示 */ #menu #list { margin: .5em 1em;填充:1em; } /* 隐藏 */ #menu:not(:hover) #list { font-size: 0;边距:0;不透明度:0;填充:0; /* 淡出,然后缩小 */ transition: opacity .25s, font-size .5s .25s, margin .5s .25s, padding .5s .25s; } /* 显示 */ #menu:hover #list { /* 取消收缩,然后淡入 */ transition: font-size .25s, margin .25s, padding .25s, opacity .5s .25s; }

另一段...


如果您有按钮或任何其他非文本元素,您最终会在不悬停时出现不需要的空白。
您可以通过使用 * 选择所有子元素并应用其他更改来进一步优化它。但是,如果按钮使用 em 正确设置样式,它们应该会受到我上面的代码的影响。
不要这样做。这不是 GPU 加速的,并且会导致非常不稳定的动画(如本答案中的片段所示)。
T
TylerH

这是具有以下属性的纯 CSS 解决方案:

开始没有延迟,过渡也没有提前停止。在两个方向(展开和折叠)中,如果您在 CSS 中指定 300 毫秒的过渡持续时间,则过渡需要 300 毫秒。

它正在转换实际高度(与 transform: scaleY(0) 不同),因此如果在可折叠元素之后有内容,它会做正确的事情。

虽然(就像在其他解决方案中一样)有一些神奇的数字(比如“选择一个比你的盒子更长的长度”),但如果你的假设最终是错误的,这并不是致命的。在这种情况下,过渡可能看起来并不惊人,但在过渡之前和之后,这不是问题:在展开(高度:自动)状态下,整个内容始终具有正确的高度(不像例如,如果你选择一个 max-结果发现高度太低)。在折叠状态下,高度应该为零。

演示

这是一个包含三个高度不同的可折叠元素的演示,它们都使用相同的 CSS。单击“运行片段”后,您可能希望单击“整页”。请注意,JavaScript 仅切换 collapsed CSS 类,不涉及测量。 (您可以使用复选框或 :target 来完成这个完全不使用任何 JavaScript 的演示)。另请注意,负责转换的 CSS 部分非常短,而 HTML 只需要一个额外的包装元素。

$(function () { $(".toggler").click(function () { $(this).next().toggleClass("collapsed"); $(this).toggleClass("toggled"); //这只是旋转扩展箭头 }); }); .collapsible-wrapper { display: flex;溢出:隐藏; } .collapsible-wrapper:after { content: '';高度:50px;过渡:高度0.3s线性,最大高度0s 0.3s线性;最大高度:0px; } .collapsible { 过渡:margin-bottom 0.3s 立方贝塞尔(0, 0, 0, 1);边距底部:0;最大高度:1000000px; } .collapsible-wrapper.collapsed > .collapsible { 边距底部:-2000px;过渡:margin-bottom 0.3s 三次贝塞尔(1, 0, 1, 1),可见性 0s 0.3s,最大高度 0s 0.3s;可见性:隐藏;最大高度:0; } .collapsible-wrapper.collapsed:after { height: 0;过渡:高度0.3s线性;最大高度:50px; } /* 可折叠实现的结束;下面的东西只是这个演示的样式 */ #container { display: flex;对齐项目:弹性开始;最大宽度:1000px;边距:0 自动; } .menu { 边框:1px 实心 #ccc;盒子阴影:0 1px 3px rgba(0,0,0,0.5);边距:20px; } .menu-item { 显示:块;背景:线性渐变(到底部,#fff 0%,#eee 100%);边距:0;填充:1em;行高:1.3; } .collapsible .menu-item { border-left: 2px solid #888;右边框:2px 实心 #888;背景:线性渐变(到底部,#eee 0%,#ddd 100%); } .menu-item.toggler { 背景:线性渐变(到底部,#aaa 0%,#888 100%);白颜色;光标:指针; } .menu-item.toggler:before { 内容:'';显示:块;左边框:8px 纯白色;边框顶部:8px 纯透明;边框底部:8px 实心透明;宽度:0;高度:0;浮动:对;过渡:变换0.3s缓出; } .menu-item.toggler.toggled:before { 变换:旋转(90度); } 正文 { 字体系列:无衬线;字体大小:14px; } *, *:after { box-sizing:border-box; }

它是如何工作的?

实际上有 两个 过渡来实现这一点。其中之一将 margin-bottom 从 0px(处于展开状态)转换为处于折叠状态的 -2000px(类似于 this answer)。这里的 2000 是第一个幻数,它基于您的框不会高于此的假设(2000 像素似乎是一个合理的选择)。

单独使用 margin-bottom 转换有两个问题:

如果您实际上有一个高于 2000 像素的框,那么 margin-bottom: -2000px 不会隐藏所有内容——即使在折叠的情况下也会有可见的东西。这是我们稍后会做的一个小修复。

如果实际的盒子是 1000 像素高,而你的过渡是 300 毫秒长,那么可见过渡在大约 150 毫秒后就已经结束(或者,在相反的方向,开始晚 150 毫秒)。

解决第二个问题是第二个过渡出现的地方,这个过渡在概念上针对包装器的 最小 高度(“概念上”,因为我们实际上并没有为此使用 min-height 属性;更多关于此之后)。

这是一个动画,它展示了如何将下边距过渡与最小高度过渡相结合,两者的持续时间相等,为我们提供了从全高到零高度的组合过渡,并且具有相同的持续时间。

https://i.stack.imgur.com/TwbsG.gif

左栏显示负底部边距如何将底部向上推,从而降低可见高度。中间条显示最小高度如何确保在折叠情况下,过渡不会提前结束,而在展开情况下,过渡不会延迟开始。右栏显示了两者的组合如何使盒子在正确的时间内从全高过渡到零高度。

对于我的演示,我已将 50px 作为最小高度值上限。这是第二个幻数,它应该低于盒子的高度。 50px 似乎也很合理;您似乎不太可能经常想要使一个最初甚至不到 50 像素高的可折叠元素。

正如您在动画中看到的那样,产生的过渡是连续的,但不可微分——在最小高度等于底部边距调整的全高的那一刻,速度突然发生变化。这在动画中非常明显,因为它对两个过渡都使用了线性计时函数,并且因为整个过渡非常慢。在实际情况下(我的演示在顶部),过渡只需要 300ms,底部边距过渡不是线性的。我已经为这两种过渡使用了许多不同的计时功能,而我最终得到的那些感觉它们在最广泛的情况下效果最好。

还有两个问题需要解决:

上面的点,其中高度超过 2000 像素的框在折叠状态下没有完全隐藏,以及相反的问题,在非隐藏的情况下,高度小于 50 像素的框即使在过渡时也太高了没有运行,因为最小高度使它们保持在 50 像素。

我们通过在折叠的情况下给容器元素一个 max-height: 0 以及一个 0s 0.3s 转换来解决第一个问题。这意味着它不是真正的过渡,但 max-height 是延迟应用的;它仅适用于过渡结束后。为了使其正常工作,我们还需要为相反的非折叠状态选择一个数字 max-height。但与 2000px 的情况不同,选择太大的数字会影响过渡的质量,在这种情况下,这真的无关紧要。所以我们可以选择一个非常高的数字,我们知道没有任何高度能接近这个数字。我选择了一百万像素。如果您觉得您可能需要支持超过一百万像素高度的内容,那么 1) 对不起,2) 只需添加几个零。

第二个问题是我们实际上没有使用 min-height 进行最小高度转换的原因。相反,容器中有一个 ::after 伪元素,其 height 从 50 像素过渡到零。这与 min-height 具有相同的效果:它不会让容器缩小到伪元素当前具有的任何高度以下。但是因为我们使用的是 height 而不是 min-height,所以我们现在可以使用 max-height(再次延迟应用)在过渡结束后将伪元素的实际高度设置为零,确保至少在过渡之外,即使是小元素也有正确的高度。因为 min-heightstronger 而不是 max-height,如果我们使用容器的 min-height 而不是伪元素的 height,这将不起作用。就像上一段中的 max-height 一样,这个 max-height 也需要一个值来表示转换的另一端。但在这种情况下,我们可以只选择 50px。

在 Chrome(Win、Mac、Android、iOS)、Firefox(Win、Mac、Android)、Edge、IE11(除了我没有费心调试的演示中的 flexbox 布局问题)和 Safari(Mac、iOS)中测试)。说到 flexbox,应该可以不使用任何 flexbox 来完成这项工作;事实上,我认为你几乎可以让 IE7 中的所有东西都工作——除了你不会有 CSS 过渡这一事实,这使它成为一个相当没有意义的练习。


我希望您可以缩短(简化)您的解决方案,或者至少是代码示例 - 看起来 90% 的代码示例与您的答案无关。
对于执行学习任务的人来说,这是一个很好的答案,原因有几个。首先,它具有完整的“现实生活”代码示例。有人可以获取该代码,对其进行试验并了解更多信息。解释中的细节……非常详细。谢谢@balpha,花时间回答这个问题:)
极好的 !这实际上工作得很好,并且经过一些修改,它也适合我的折叠元素不处于 0 高度的用例(在我的情况下,网格在折叠时仅显示一行,并在打开时显示所有行)。不仅如此,它似乎很容易在各种环境中实现,可以“插入”现有页面,而不必更改太多的父子元素,这是许多其他解决方案无法做到的。
感谢所有的彻底性,但是,在这里有点坚持,动画看起来和感觉都很糟糕。一天结束时不是一个平滑的计时功能。这是这种方法固有的吗?
@StevenLu 在某种程度上,是的。我在回答中解决了这个问题,请参阅以“这在动画中非常明显......”开头的句子
S
Spencer O'Reilly

你可以,用一点非语义的猜谜扑克。我常用的方法是为具有单个子元素的外部 DIV 的高度设置动画,该子元素是无样式 DIV,仅用于测量内容高度。

函数 growDiv() { var growDiv = document.getElementById('grow'); if (growDiv.clientHeight) { growDiv.style.height = 0; } else { var wrapper = document.querySelector('.measuringWrapper'); growDiv.style.height = wrapper.clientHeight + "px"; } } #grow { -moz-transition: 高度 .5s; -ms-transition:高度 0.5s; -o-过渡:高度 0.5 秒; -webkit-transition:高度 0.5s;过渡:高度 0.5s;高度:0;溢出:隐藏;轮廓:1px 纯红色; }

我的 div 的内容。
我的 div 的内容。
我的 div 的内容。
我的 div 的内容。
我的 div 的内容。
我的 div 的内容。

人们希望能够省去 .measuringWrapper 并将 DIV 的高度设置为 auto 并进行动画处理,但这似乎不起作用(设置了高度,但没有动画发生)。

函数 growDiv() { var growDiv = document.getElementById('grow'); if (growDiv.clientHeight) { growDiv.style.height = 0; } else { growDiv.style.height = 'auto'; } } #grow { -moz-transition: 高度 .5s; -ms-transition:高度 0.5s; -o-过渡:高度 0.5 秒; -webkit-transition:高度 0.5s;过渡:高度 0.5s;高度:0;溢出:隐藏;轮廓:1px 纯红色; }

我的 div 的内容。
我的 div 的内容。
我的 div 的内容。
我的 div 的内容。
我的 div 的内容。
我的 div 的内容。

我的解释是动画运行需要一个明确的高度。当任一高度(开始或结束高度)为 auto 时,您无法获得高度动画。


由于这依赖于javascript,您也可以使用javascript轻松添加measurementWrapper!
你可以在没有包装的情况下做到这一点。只是: function growDiv() { var growDiv = document.getElementById('grow'); if (growDiv.clientHeight) { growDiv.style.height = 0; } else { growDiv.style.height = growDiv.scrollHeight+'px'; } }
我更喜欢这种方法,因为它很精确。我还喜欢根据计算出的高度来调整折叠元素的过渡速度。这样,高大的元素比矮小的元素需要成比例地更长的时间来展开。即folder.style.transition = `height ${maxHeight}ms`;
J
Joran Den Houting

使用 CSS3 过渡为高度设置动画的一种视觉解决方法是为填充设置动画。

您并没有完全获得完整的擦除效果,但是使用 transition-duration 和 padding 值应该可以让您足够接近。如果您不想明确设置高度/最大高度,这应该是您正在寻找的。

div {
    height: 0;
    overflow: hidden;
    padding: 0 18px;
    -webkit-transition: all .5s ease;
       -moz-transition: all .5s ease;
            transition: all .5s ease;
}
div.animated {
    height: auto;
    padding: 24px 18px;
}

http://jsfiddle.net/catharsis/n5XfG/17/(从 stephband 上面的 jsFiddle 中提取)


除了在这里你根本没有为高度设置动画。您正在为填充设置动画......它可以很好地消失,因为它可以从当前状态动画到 0,但是如果你仔细观察它展开时它会弹出文本,然后填充只有动画......因为它没有'不知道如何从 0 动画到自动......它需要一个数值范围......这就是补间的工作原理。
我不知道如何用一种不粗鲁的方式来表达这个,但是......它看起来不专业。至少 stackoverflow.com/a/30531678/340947 使运动“连续”......但它并不平滑
O
Oleg Vaskevich

接受的答案适用于大多数情况,但当您的 div 高度变化很大时,它就不能很好地工作 - 动画速度不依赖于内容的实际高度,它可能看起来不连贯。

您仍然可以使用 CSS 执行实际动画,但您需要使用 JavaScript 来计算项目的高度,而不是尝试使用 auto。不需要 jQuery,但如果你想要兼容性,你可能需要稍微修改一下(在最新版本的 Chrome 中工作 :))。

window.toggleExpand = function(element) { if (!element.style.height || element.style.height == '0px') { element.style.height = Array.prototype.reduce.call(element.childNodes, function (p, c) {return p + (c.offsetHeight || 0);}, 0) + 'px'; } 其他 { element.style.height = '0px'; } } #menu #list { 高度:0px;过渡:高度 0.3s 缓动;背景:#d5d5d5;溢出:隐藏; }


@Coderer 你可以使用 clientHeight
这有一个非常好的结果。但是 JavaScript 在很大程度上看起来像机器代码。你怎么能像说英语一样重写代码(可读代码)?
您也可以在高度为 0 时使用 scrollHeight
a
amn

几乎没有提到 Element.prototype.scrollHeight 属性,它在这里很有用,仍然可以与纯 CSS 过渡一起使用,尽管显然需要脚本支持。该属性始终包含元素的“完整”高度,无论其内容是否以及如何由于折叠高度(例如 height: 0)而溢出。

因此,对于 height: 0(实际上完全折叠)元素,其“正常”或“完整”高度仍可通过其 scrollHeight 值(始终为 pixel 长度)轻松获得。

对于这样的元素,假设它已经设置了转换(根据原始问题使用 ul):

ul {
    height: 0;
    transition: height 1s; /* An example transition. */
}

我们可以触发所需的动画“扩展”高度,仅使用 CSS,如下所示(这里假设 ul 变量指的是列表):

ul.style.height = ul.scrollHeight + "px";

而已。如果您需要折叠列表,以下两个语句中的任何一个都可以:

ul.style.height = 0;
ul.style.removeProperty("height");

我的特定用例围绕未知且通常相当长的动画列表展开,因此我不习惯处理“足够大”的 heightmax-height 规范并冒着截断内容或您突然需要滚动的内容的风险(如果overflow: auto,例如)。此外,基于 max-height 的解决方案破坏了缓动和计时,因为使用的高度可能比 max-height 达到 9999px 所需的时间早得多。随着屏幕分辨率的提高,像 9999px 这样的像素长度在我的嘴里留下了不好的味道。在我看来,这个特殊的解决方案以一种优雅的方式解决了这个问题。

最后,希望未来的 CSS 版本能够解决作者需要更优雅地做这些事情——重新审视“计算”与“使用”和“已解决”值的概念,并考虑转换是否应该适用于计算值,包括带有 widthheight 的转换(目前得到了一些特殊处理)。


您没有在此处的其他答案中找到它,因为使用 Element.scrollHeight 属性与 DOM 交互需要 JavaScript,并且正如问题明确指出的那样,他们希望 不使用 JavaScript 来执行此操作。
a
amn

我的解决方法是将 max-height 转换为精确的内容高度以获得流畅的动画效果,然后使用 transitionEnd 回调将 max-height 设置为 9999px,以便内容可以自由调整大小。

var 内容 = $('#content'); content.inner = $('#content .inner'); // 关闭时需要获取内容大小的内部 div // css 转换回调 content.on('transitionEnd webkitTransitionEnd transitionend oTransitionEnd msTransitionEnd', function(e){ if(content.hasClass('open')){ content.css( 'max-height', 9999); // 尝试将其设置为 'none'...我敢! } }); $('#toggle').on('click', function(e){ content.toggleClass('open closed'); content.contentHeight = content.outerHeight(); if(content.hasClass('close')) { // 禁用过渡并将 max-height 设置为内容高度 content.removeClass('transitions').css('max-height', content.contentHeight); setTimeout(function(){ // 启用并开始过渡 content.addClass ('transitions').css({ 'max-height': 0, 'opacity': 0 }); }, 10); // 10ms 超时是禁用/启用转换的秘诀 // chrome 只需要 1ms 但FF 需要大约 10 毫秒,否则由于某种原因它在第一个动画上阻塞 }else if(content.hasClass('open')){ content.contentHeight += content.inner.outerHeight(); // 如果关闭,则添加内部高度内容高度 content.css({ 'max-height': content.contentHeight, 'opacity': 1 }); } }); .transitions { transition: all 0.5s ease-in-out; -webkit-transition:所有 0.5s 缓入出局; -moz-transition:所有 0.5s 缓入缓出; } 正文 { 字体系列:宋体;行高:3ex; } 代码 { 显示:内联块;背景:#fafafa;填充:0 1ex; } #toggle { 显示:块;填充:10px;边距:10px 自动;文本对齐:居中;宽度:30ex; } #content { 溢出:隐藏;边距:10px;边框:1px 实心 #666;背景:#efefef;不透明度:1; } #content .inner { 填充:10px;溢出:自动; }

height: 0height: auto

之间的平滑 CSS 过渡

一个聪明的解决方法是使用 < code>max-height 而不是 height,并将其设置为比您的内容更大的值。问题是浏览器使用这个值来计算转换持续时间。因此,如果您将其设置为 max-height: 1000px 但内容只有 100px 高,则动画将快 10 倍。

另一种选择是使用JS 并转换到那个固定值,但是你必须跟踪内容并在它发生变化时手动调整它的大小。

这个解决方案是两者的混合 - 转换到测量的内容高度,然后在转换后将其设置为 max-height: 9999px 以实现流畅的内容大小调整。


m
malihu

对每个状态使用具有不同过渡缓动和延迟的 max-height

HTML:

<a href="#" id="trigger">Hover</a>
<ul id="toggled">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
<ul>

CSS:

#toggled{
    max-height: 0px;
    transition: max-height .8s cubic-bezier(0, 1, 0, 1) -.1s;
}

#trigger:hover + #toggled{
    max-height: 9999px;
    transition-timing-function: cubic-bezier(0.5, 0, 1, 0); 
    transition-delay: 0s;
}

参见示例:http://jsfiddle.net/0hnjehjc/1/


这里的问题是,为了确保您在动态环境中有足够的空间,您需要使用像 999999px 这样荒谬的最大高度。另一方面,这会改变你的动画,因为帧是根据这个值计算的。因此,您最终可能会在一个方向上出现动画“延迟”,而在另一个方向上会很快结束(更正:计时功能)
V
V Maharajh

没有硬编码值。

没有 JavaScript。

没有近似值。

诀窍是使用隐藏的 &复制 div 以使浏览器了解 100% 的含义。

只要您能够复制要制作动画的元素的 DOM,此方法就适用。

.outer { 边框:红色虚线 1px;位置:相对; } .dummy { 可见性:隐藏; } .real { 位置:绝对;背景:黄色;高度:0;过渡:高度0.5s;溢出:隐藏; } .outer:hover>.real { 高度:100%; } 将鼠标悬停在下面的框上:

不可预测的内容 不可预测的内容 不可预测的内容 不可预测的内容 不可预测的内容不可预测的内容 不可预测的内容 不可预测的内容 不可预测的内容 不可预测的内容 不可预测的内容 不可预测的内容 不可预测的内容 不可预测的内容 不可预测的内容


C
Community

当我发布这篇文章时,已经有 30 多个答案,但我觉得我的答案比 jake 的 accepted answer 有所改进。

我不满足于仅使用 max-height 和 CSS3 过渡所产生的问题,因为正如许多评论者指出的那样,您必须将 max-height 值设置为非常接近实际高度,否则会出现延迟。有关该问题的示例,请参阅此 JSFiddle

为了解决这个问题(仍然不使用 JavaScript),我添加了另一个 HTML 元素来转换 transform: translateY CSS 值。

这意味着 max-heighttranslateY 都被使用了:max-height 允许元素将元素下推到它下面,而 translateY 给出了我们想要的“即时”效果。 max-height 的问题仍然存在,但其影响已减弱。这意味着您可以为 max-height 值设置更大的高度并减少对其的担心。

总体好处是,在返回(折叠)过渡时,用户会立即看到 translateY 动画,因此 max-height 需要多长时间并不重要。

Solution as Fiddle

正文 { 字体系列:无衬线; } .toggle { 位置:相对;边框:2px 实心 #333;边框半径:3px;边距:5px;宽度:200px; } .toggle-header { 边距:0;填充:10px;背景颜色:#333;白颜色;文本对齐:居中;光标:指针; } .toggle-height { 背景色:番茄;溢出:隐藏;过渡:最大高度 .6s 缓动;最大高度:0; } .toggle:hover .toggle-height { max-height: 1000px; } .toggle-transform { 填充:5px;白颜色;过渡:变换 .4s 缓和;变换:translateY(-100%); } .toggle:hover .toggle-transform { transform: translateY(0); }

切换!

内容!

内容!

内容!

内容!

切换!

内容!

内容!

内容!

内容!


“并不重要”仍然是相当主观的。转换转换的即时反馈当然很好,但这肯定还有一些不足之处
M
Mori

根据 MDN Web Docsauto 值已被有意从 CSS 过渡规范中排除,因此在网格和 flex 布局中使用 height: 100%topflex 属性来代替 height: auto

展开/折叠覆盖

.grid-container { 显示:网格;位置:绝对; } .content { 背景:水色;高度:0;溢出:隐藏;过渡:1s; } 跨度:悬停 + .grid-container .content { 高度:100%; } 悬停在我身上!

Lorem ipsum dolor sit amet,consectetur adipiscing elit,sed do eiusmod tempor incididunt ut labore et dolore magna阿里夸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。 Exceptioneur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est labourum。

其余页面内容...

展开/折叠滑动覆盖

.grid-container { 显示:网格;位置:绝对;溢出:隐藏;指针事件:无; /* 启用与容器下方元素的交互 */ } .content { background: aqua;指针事件:自动;位置:相对;最高:-100%;过渡:1s; } 跨度:悬停 + .grid-container .content { 顶部:0; } 悬停在我身上!

Lorem ipsum dolor sit amet,consectetur adipiscing elit,sed do eiusmod tempor incididunt ut labore et dolore magna阿里夸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。 Exceptioneur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est labourum。

其余页面内容...

在文档流中展开/折叠

html {显示:网格; } 身体 { 显示:弹性;弹性方向:列; } .content { 背景:水色;弹性基础:0;溢出:隐藏;过渡:1s; } span:hover + .content { flex: 1; } 悬停在我身上!

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。 Exceptioneur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est labourum。

页面的其余内容...


我对这个例子很兴奋:Expanding/collapsing in the document flow 但它不起作用,因为容器有一个定义的高度,所以其余的内容会受到影响,容器外的内容,
是的!感谢分享,如果我认为是这样,在某些情况下,如果您在内容的末尾超出间距并不重要,在内容是整页的情况下,您将始终在末尾有数不清的间距
@MarcoMesen:刚刚编辑了我的示例。
嘿@Mori 谢谢!效果很好,我们基本上是为 Grid 的扩展设置动画,但秘诀是内部 Flex,非常感谢!
@Mori 在这种情况下它可以工作,但通常不容易更改整个页面的标记,将 body 用作 flex 容器并将展开/折叠元素放在它的正下方,只是为了达到这种效果。另外,你将如何解决两个相邻的扩展元素并且每个元素都将相同的内容下推到它下面?
V
VIDesignz

好的,所以我想我想出了一个超级简单的答案...没有 max-height,使用 relative 定位,适用于 li 元素,&是纯CSS。除了 Firefox,我没有在任何东西上测试过,虽然从 CSS 来看,它应该适用于所有浏览器。

小提琴:http://jsfiddle.net/n5XfG/2596/

CSS

.wrap { overflow:hidden; }

.inner {
            margin-top:-100%;
    -webkit-transition:margin-top 500ms;
            transition:margin-top 500ms;
}

.inner.open { margin-top:0px; }

HTML

<div class="wrap">
    <div class="inner">Some Cool Content</div>
</div>

这将一直有效,直到元素的高度超过其宽度。它是使用百分比计算边距的基础:它们是根据元素的宽度计算的。因此,如果您有一个 1000 px 宽的元素,那么 1100 px 的元素对于此解决方案来说太大了,这意味着您必须增加负上边距。基本上,这与使用高度或最大高度完全相同。
S
Sijav

编辑:向下滚动以获取更新的答案
我正在制作一个下拉列表并看到这篇文章......许多不同的答案,但我决定也分享我的下拉列表,......它并不完美,但至少它会使用只有 CSS 用于下拉!我一直在使用 transform:translateY(y) 将列表转换为视图 ...
您可以在测试中看到更多信息
http://jsfiddle.net/BVEpc/4/
我将 div 放在每个 li 后面,因为我的下拉列表来自向上并正确显示它们这是需要的,我的 div 代码是:

#menu div {
    transition: 0.5s 1s;
    z-index:-1;
    -webkit-transform:translateY(-100%);
    -webkit-transform-origin: top;
}

悬停是:

#menu > li:hover div {
    transition: 0.5s;
    -webkit-transform:translateY(0);
}

并且因为 ul 高度设置为内容,它可以超越您的身体内容,这就是我为 ul 这样做的原因:

 #menu ul {
    transition: 0s 1.5s;
    visibility:hidden;
    overflow:hidden;
}

并悬停:

#menu > li:hover ul {
     transition:none;
     visibility:visible;
}

过渡后的第二次是延迟,它会在我的下拉列表动画关闭后被隐藏...
希望以后有人能从中受益。

编辑:我简直不敢相信 ppl 居然在使用这个原型!此下拉菜单仅适用于一个子菜单,仅此而已!我更新了一个更好的菜单,它可以有两个子菜单,用于 ltr 和 rtl 方向,并支持 IE 8。
Fiddle for LTR
Fiddle for RTL
希望将来有人会发现这很有用。


J
Joran Den Houting

您可以从 height:0 过渡到 height:auto,前提是您还提供了最小高度和最大高度。

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

div.stretchy.visible{
    height: auto;
    min-height:40px;
    max-height:400px;
}

这不会转换 height,只会转换 max-heightheight 将立即从 0 跳转到 auto,而 max-height 将进行转换,这似乎有效,但会产生与其他答案试图解决的相同问题。
当我可以估计最大高度并且不关心动画的确切长度时,这实际上是个好主意并且有效。
L
Lee Comstock

弹性盒解决方案

优点:

简单的

没有JS

平稳过渡

缺点:

元素需要放在一个固定高度的弹性容器中

它的工作方式是始终在具有内容的元素上使用 flex-basis: auto ,并转换为 flex-grow 和 flex-shrink 。

编辑:受 Xbox One 界面启发的改进的 JS Fiddle。

{边距:0;填充:0; box-sizing:边框框;过渡:0.25s;字体系列:等宽; } 正文 { 边距:10px 0 0 10px; } .box { 宽度:150px;高度:150px;边距:0 2px 10px 0;背景:#2d333b;边框:实心 10px #20262e;溢出:隐藏;显示:inline-flex;弹性方向:列; } .space { 弹性基础:100%;弹性增长:1;弹性收缩:0; } p { 弹性基础:自动;弹性增长:0;弹性收缩:1;背景:#20262e;填充:10px;宽度:100%;文本对齐:左;白颜色; } .box:hover .space { flex-grow: 0;弹性收缩:1; } .box:hover p { flex-grow: 1;弹性收缩:0; }

Super Metroid Prime Fusion

生化危机 2 重制版

Yolo The Game

Final Fantasy 7 Remake + 所有附加 DLC + Golden Tophat

DerpVille

JS Fiddle


我喜欢这个解决方案。连同绝对定位、嵌套列表和指针事件,我设法得到了一个相当不错的菜单。我没有发现很多负面因素。有人吗?
我的 JSFiddle 中的 CSS 因某种原因坏了,但是我喜欢这个解决方案,谢谢!
d
dallaslu

一句话解决方案:使用填充过渡。对于大多数情况(例如手风琴)来说已经足够了,甚至更好,因为它的速度很快,因为填充值通常不大。

如果您希望动画过程更好,只需提高填充值即可。

.parent{border-top: #999 1px solid;} h1{ margin: .5rem;字体大小:1.3rem} .children { 高度:0;溢出:隐藏;背景颜色:#dedede;过渡:填充 .2s 缓入出,不透明度 .2s 缓入出;填充:0 .5rem;不透明度:0; } .children::before, .children::after{ content: "";display: block;} .children::before{ margin-top: -2rem;} .children::after{ margin-bottom: -2rem; } .parent:hover .children { 高度:自动;不透明度:1; padding: 2.5rem .5rem;/* 0.5 + abs(-2), 确保小于预期的最小高度 */ }

Hover me

部分内容
部分内容
部分内容
部分内容
部分内容
部分内容

悬停我(长内容)

部分内容
部分内容
部分内容
部分内容
部分内容
部分内容
一些内容
一些内容
一些内容
一些内容
一些内容

悬停我(短内容)

部分内容
部分内容
部分内容


J
Joran Den Houting

扩展@jake 的答案,过渡将一直到最大高度值,从而产生极快的动画-如果您为 :hover 和 off 设置过渡,则可以进一步控制疯狂的速度。

所以 li:hover 是鼠标进入状态,然后非悬停属性上的转换将是鼠标离开。

希望这会有所帮助。

例如:

.sidemenu li ul {
   max-height: 0px;
   -webkit-transition: all .3s ease;
   -moz-transition: all .3s ease;
   -o-transition: all .3s ease;
   -ms-transition: all .3s ease;
   transition: all .3s ease;
}
.sidemenu li:hover ul {
    max-height: 500px;
    -webkit-transition: all 1s ease;
   -moz-transition: all 1s ease;
   -o-transition: all 1s ease;
   -ms-transition: all 1s ease;
   transition: all 1s ease;
}
/* Adjust speeds to the possible height of the list */

这是一个小提琴:http://jsfiddle.net/BukwJ/


T
TylerH

该解决方案使用了一些技术:

padding-bottom:100% 'hack' 其中百分比是根据元素的当前宽度定义的。有关此技术的更多信息。

浮动收缩包装,(需要一个额外的 div 来应用浮动清除黑客)

非语义使用 https://caniuse.com/#feat=css-writing-mode 和一些转换来撤消它(这允许在垂直上下文中使用上面的填充黑客)

结果是我们只使用 CSS 获得了高性能的过渡,以及一个平滑的过渡函数来实现过渡;圣杯!

当然,也有缺点!我不知道如何控制内容被截断的宽度(overflow:hidden);由于 padding-bottom hack,宽度和高度密切相关。不过可能有办法,所以会回到它。

https://jsfiddle.net/EoghanM/n1rp3zb4/28/

身体{填充:1em; } .trigger { 字体粗细:粗体; } /* .expander 仅用于清除浮动 */ .expander::after { content: '';显示:表格;明确:两者; } .outer { 浮动:左; /* 目的:缩小以适应内容 */ 边框:1px 纯绿色;溢出:隐藏; } .inner { transition: padding-bottom 0.3s ease-in-out; /* 或者你能想出的任何疯狂的转换函数! */ padding-bottom: 0%; /* 百分比填充是根据宽度定义的。这一层的宽度等于内容的高度 */ height: 0; /* 不幸的是,改变书写模式还有其他不好的影响,比如光标方向 */ writing-mode: vertical-rl;光标:默认; /* 不想要垂直文本(横向工字梁)*/ transform: rotate(-90deg) translateX(-100%); /* 撤消写入模式 */ transform-origin: 0 0;边距:0; /* 这里的左/右边距将增加高度 */ } .inner > div { white-space: nowrap; } .expander:hover .inner, /* 展开时保持打开 */ .trigger:hover+.expander .inner { padding-bottom: 100%; }

HoverMe
第一项
内容
内容
内容
不幸的是,长内容不能超过外部高度
最后一项
在内容之后


正如您的消息来源所说的“响应式正方形”,它仅在您具有正方形内容时才有效。所以它甚至不接近公认的答案......
T
TylerH

您可以通过使用剪辑路径创建反向(折叠)动画来做到这一点。

#child0 { 显示:无; } #parent0:hover #child0 { 显示:块;动画:高度动画;动画持续时间:200ms;动画定时功能:线性;动画填充模式:向后;动画迭代计数:1;动画延迟:200ms; } @keyframes 高度动画 { 0% { 剪辑路径:多边形(0% 0%, 100% 0.00%, 100% 0%, 0% 0%); } 100% { 剪辑路径:多边形(0% 0%, 100% 0.00%, 100% 100%, 0% 100%); } }

悬停在我身上(高度:0)

部分内容
部分内容
部分内容
部分内容< br>部分内容
部分内容


太好了,但是如何用动画取消显示?
J
Jonatas Walker

我最近一直在转换 li 元素上的 max-height 而不是包装 ul

原因是与大 max-heights 相比,小 max-heights 的延迟远不那么明显(如果有的话),我还可以将我的 max-height 值设置为相对于 lifont-size 而不是通过使用 emsrems 获得一些任意的大数。

如果我的字体大小是 1rem,我会将 max-height 设置为 3rem(以适应换行的文本)。你可以在这里看到一个例子:

http://codepen.io/mindfullsilence/pen/DtzjE


s
shunryu111

我理解这个问题要求没有 JavaScript 的解决方案。但对于那些感兴趣的人来说,这是我使用一点 JS 的解决方案。

好的,所以默认情况下高度会改变的元素的css设置为height: 0;,打开时为height: auto;。它也有 transition: height .25s ease-out;。但当然问题是它不会转换到或从 height: auto;

所以我所做的是在打开或关闭时将高度设置为元素的 scrollHeight 属性。这种新的内联样式将具有更高的特异性并覆盖 height: auto;height: 0; 并运行转换。

打开时,我添加了一个 transitionend 事件侦听器,它只会运行一次,然后删除内联样式,将其设置回 height: auto;,这将允许元素在必要时调整大小,如这个带有子菜单 https://codepen.io/ninjabonsai/pen/GzYyVe 的更复杂的示例

关闭时,我在下一个 event loop 周期后立即使用 setTimeout 删除内联样式,没有延迟。这意味着 height: auto; 被暂时覆盖,从而允许转换回 height 0;

const showHideElement = (element, open) => { element.style.height = element.scrollHeight + 'px'; element.classList.toggle('open', open); if (open) { element.addEventListener('transitionend', () => { element.style.removeProperty('height'); }, { once: true }); } else { window.setTimeout(() => { element.style.removeProperty('height'); }); } } const menu = document.body.querySelector('#menu'); const list = document.body.querySelector('#menu > ul') menu.addEventListener('mouseenter', () => showHideElement(list, true)); menu.addEventListener('mouseleave', () => showHideElement(list, false)); #menu > ul { 高度:0;溢出:隐藏;背景颜色:#999;过渡:高度 0.25 秒缓出; } #menu > ul.open { 高度:自动; }


c
csuwldcat

这是一种从任何起始高度(包括 0)过渡到自动(全尺寸和灵活)的方法,无需基于每个节点的硬设置代码或任何用户代码进行初始化:https://github.com/csuwildcat/transition-auto。这基本上是你想要的圣杯,我相信 --> http://codepen.io/csuwldcat/pen/kwsdF。只需将以下 JS 文件添加到您的页面中,之后您需要做的就是从要扩展和收缩的节点中添加/删除单个布尔属性 - reveal=""

这是您作为用户需要做的所有事情,一旦您包含示例代码下方的代码块:

/*** Nothing out of the ordinary in your styles ***/
<style>
    div {
        height: 0;
        overflow: hidden;
        transition: height 1s;
    }
</style>

/*** Just add and remove one attribute and transition to/from auto! ***/

<div>
    I have tons of content and I am 0px in height you can't see me...
</div>

<div reveal>
     I have tons of content and I am 0px in height you can't see me...
     but now that you added the 'reveal' attribute, 
     I magically transitioned to full height!...
</div>

这是要包含在您的页面中的代码块,之后,它就是所有的肉汁:

将这个 JS 文件放到你的页面中——这一切都只是 Works™

/* 高度代码:auto;过渡*/

(function(doc){

/* feature detection for browsers that report different values for scrollHeight when an element's overflow is hidden vs visible (Firefox, IE) */
var test = doc.documentElement.appendChild(doc.createElement('x-reveal-test'));
    test.innerHTML = '-';
    test.style.cssText = 'display: block !important; height: 0px !important; padding: 0px !important; font-size: 0px !important; border-width: 0px !important; line-height: 1px !important; overflow: hidden !important;';
var scroll = test.scrollHeight || 2;
doc.documentElement.removeChild(test);

var loading = true,
    numReg = /^([0-9]*\.?[0-9]*)(.*)/,
    skipFrame = function(fn){
      requestAnimationFrame(function(){
        requestAnimationFrame(fn);
      });
    },
    /* 2 out of 3 uses of this function are purely to work around Chrome's catastrophically busted implementation of auto value CSS transitioning */
    revealFrame = function(el, state, height){
        el.setAttribute('reveal-transition', 'frame');
        el.style.height = height;
        skipFrame(function(){
            el.setAttribute('reveal-transition', state);
            el.style.height = '';
        });
    },
    transitionend = function(e){
      var node = e.target;
      if (node.hasAttribute('reveal')) {
        if (node.getAttribute('reveal-transition') == 'running') revealFrame(node, 'complete', '');
      } 
      else {
        node.removeAttribute('reveal-transition');
        node.style.height = '';
      }
    },
    animationstart = function(e){
      var node = e.target,
          name = e.animationName;   
      if (name == 'reveal' || name == 'unreveal') {

        if (loading) return revealFrame(node, 'complete', 'auto');

        var style = getComputedStyle(node),
            offset = (Number(style.paddingTop.match(numReg)[1])) +
                     (Number(style.paddingBottom.match(numReg)[1])) +
                     (Number(style.borderTopWidth.match(numReg)[1])) +
                     (Number(style.borderBottomWidth.match(numReg)[1]));

        if (name == 'reveal'){
          node.setAttribute('reveal-transition', 'running');
          node.style.height = node.scrollHeight - (offset / scroll) + 'px';
        }
        else {
            if (node.getAttribute('reveal-transition') == 'running') node.style.height = '';
            else revealFrame(node, 'running', node.scrollHeight - offset + 'px');
        }
      }
    };

doc.addEventListener('animationstart', animationstart, false);
doc.addEventListener('MSAnimationStart', animationstart, false);
doc.addEventListener('webkitAnimationStart', animationstart, false);
doc.addEventListener('transitionend', transitionend, false);
doc.addEventListener('MSTransitionEnd', transitionend, false);
doc.addEventListener('webkitTransitionEnd', transitionend, false);

/*
    Batshit readyState/DOMContentLoaded code to dance around Webkit/Chrome animation auto-run weirdness on initial page load.
    If they fixed their code, you could just check for if(doc.readyState != 'complete') in animationstart's if(loading) check
*/
if (document.readyState == 'complete') {
    skipFrame(function(){
        loading = false;
    });
}
else document.addEventListener('DOMContentLoaded', function(e){
    skipFrame(function(){
        loading = false;
    });
}, false);

/* Styles that allow for 'reveal' attribute triggers */
var styles = doc.createElement('style'),
    t = 'transition: none; ',
    au = 'animation: reveal 0.001s; ',
    ar = 'animation: unreveal 0.001s; ',
    clip = ' { from { opacity: 0; } to { opacity: 1; } }',
    r = 'keyframes reveal' + clip,
    u = 'keyframes unreveal' + clip;

styles.textContent = '[reveal] { -ms-'+ au + '-webkit-'+ au +'-moz-'+ au + au +'}' +
    '[reveal-transition="frame"] { -ms-' + t + '-webkit-' + t + '-moz-' + t + t + 'height: auto; }' +
    '[reveal-transition="complete"] { height: auto; }' +
    '[reveal-transition]:not([reveal]) { -webkit-'+ ar +'-moz-'+ ar + ar +'}' +
    '@-ms-' + r + '@-webkit-' + r + '@-moz-' + r + r +
    '@-ms-' + u +'@-webkit-' + u + '@-moz-' + u + u;

doc.querySelector('head').appendChild(styles);

})(document);

/* 演示代码 */

    document.addEventListener('click', function(e){
      if (e.target.nodeName == 'BUTTON') {
        var next = e.target.nextElementSibling;
        next.hasAttribute('reveal') ? next.removeAttribute('reveal') : next.setAttribute('reveal', '');
      }
    }, false);

我想对此表示赞同,但您没有回答如何使其工作的问题,而是共享了一个您编写的插件以使其工作。好奇的我们只能对您的插件进行逆向工程,这并不好玩。我希望你能更新你的答案,以包含更多关于你的插件的作用和原因的解释。更改代码以更具说明性。例如,你有一整段代码只写出静态 CSS。我宁愿看到 CSS,也不愿看到生成它的代码。您可以省略无聊的部分,例如对所有浏览器前缀重复。
J
JonTroncoso

我想我想出了一个非常可靠的解决方案

好的!我知道这个问题与互联网一样古老,但我想我有一个解决方案,我把它变成了 plugin called mutant-transition。每当 DOM 发生变化时,我的解决方案都会为被跟踪元素设置 style="" 属性。最终结果是您可以使用良好的 ole CSS 进行转换,而无需使用 hacky 修复或特殊的 javascript。您唯一需要做的就是使用 data-mutant-attributes="X" 设置您想要在相关元素上跟踪的内容。

<div data-mutant-attributes="height">                                                                      
        This is an example with mutant-transition                                                                                                          
    </div>

而已!此解决方案使用 MutationObserver 跟踪 DOM 中的更改。正因为如此,您实际上不必设置任何东西或使用 javascript 来手动设置动画。自动跟踪更改。但是,因为它使用了 MutationObserver,所以这只会在 IE11+ 中转换。

小提琴!

演示从 height: auto 到 height: 100% 的过渡

演示过渡高度:添加孩子时自动


通常,当有人询问如何“不使用 JavaScript”时,这意味着该解决方案必须适用于禁用 JavaScript 的浏览器。这并不意味着“不编写自己的脚本”。所以说你的插件可以在不使用 JavaScript 的情况下使用最多是误导 - 考虑到它是一个 JavaScript 插件。
我应该澄清一下,当我说您不必使用任何特殊的 javascript 时,我的意思是您不必编写任何 javascript。只需包含 JS 库并指定要在 HTML 中查看的属性。您不必使用固定高度的 css,也不必想出任何办法。只是风格和去。
u
user3336882

Jake 对 max-height 进行动画处理的答案很棒,但我发现设置较大的 max-height 造成的延迟很烦人。

可以将可折叠内容移动到内部 div 中,并通过获取内部 div 的高度来计算最大高度(通过 JQuery,它将是 outerHeight())。

$('button').bind('click', function(e) { 
  e.preventDefault();
  w = $('#outer');
  if (w.hasClass('collapsed')) {
    w.css({ "max-height": $('#inner').outerHeight() + 'px' });
  } else {
    w.css({ "max-height": "0px" });
  }
  w.toggleClass('collapsed');
});

这是一个 jsfiddle 链接:http://jsfiddle.net/pbatey/duZpT

这是一个所需代码最少的 jsfiddle:http://jsfiddle.net/8ncjjxh8/


J
Jonatas Walker

我能够做到这一点。我有一个 .child & .parent 格。通过 absolute 定位,子 div 完全适合父级的宽度/高度。然后,我为 translate 属性设置动画以将其 Y 值向下推 100%。它的动画非常流畅,没有像这里的任何其他解决方案那样出现故障或缺点。

像这样的东西,伪代码

.parent{ position:relative; overflow:hidden; } 
/** shown state */
.child {
  position:absolute;top:0;:left:0;right:0;bottom:0;
  height: 100%;
  transition: transform @overlay-animation-duration ease-in-out;
  .translate(0, 0);
}

/** Animate to hidden by sliding down: */
.child.slidedown {
  .translate(0, 100%); /** Translate the element "out" the bottom of it's .scene container "mask" so its hidden */
}

您可以在 .parentpx% 中指定一个 height,或者保留为 auto。然后,当它向下滑动时,此 div 会掩盖 .child div。


这方面的工作示例将不胜感激。
A
Ali Klein

使用 line-heightpaddingopacitymargin 的备用纯 CSS 解决方案:

身体{背景颜色:亚麻; } 主要 { 背景颜色:白色; } [id^="toggle_"] ~ .content { line-height: 0;不透明度:0;填充:0 .5rem;过渡:.2s 缓出; } [id^="toggle_"] ~ .content > p { 边距:0;过渡:.2s 缓出; } [id^="toggle_"]:checked ~ .content { opacity: 1;填充:0.5rem;行高:1.5; } [id^="toggle_"]:checked ~ .content p { margin-bottom: .75rem; } [id^="toggle_"] + 标签 { 显示:弹性; justify-content: 之间的空格;填充:0.5em 1em;背景:轻钢蓝;边框底部:1px 纯灰色;光标:指针; } [id^="toggle_"] + 标签:之前 { 内容:“显示”; } [id^="toggle_"]:checked + label:before { content: "Hide"; } [id^="toggle_"] + 标签:在 { 内容之后:"\25BC"; } [id^="toggle_"]:checked + label:after { content: "\25B2"; }

Lorem ipsum dolor sit amet , consectetur adipiscing 精英。 Duis dolor neque, commodo quis leo ut, 拍卖师 tincidunt mauris。 Nunc fringilla tincidunt metus,non gravida lorem condimentum non。 Duis ornare purus nisl,位于 porta arcu eleifend eget。整数 lorem ante,porta vulputate dui ut,blandit tempor tellus。 Proin facilisis bibendum diam,坐在 amet rutrum est feugiat ut。 Mauris rhoncus convallis arcu 在调味品中。 Donec volutpat dui eu mollis vulputate。 Nunc commodo lobortis nunc 在 ultrices。吊挂在 lobortis 直径。 Suspendisse eget 前庭前庭。

Maecenas laoreet nunc sat amet nulla ultrices auctor。 Vivamus sed nisi vitae nibh condimentum pulvinar eu vel lorem。 Sed pretium viverra eros ut facilisis。在ut fringilla magna。 Sed 一个临时自由人。 Donec sapien libero, lacinia sed aliquet ut, imperdiet finibus tellus。 Nunc tellus lectus, rhoncus in posuere quis, tempus sit amet enim。 Morbi et erat ac velit fringilla dignissim。 Donec commodo,est id accumsan cursus,diam dui hendrerit nisi,vel hendrerit purus dolor ut risus。 Phasellus mattis egestas ipsum sed ullamcorper。在 diam ligula,rhoncus vel enim et,imperdiet porta justo。 Curabitur vulputate hendrerit nisl,et ultricies diam。 Maecenas ac leo a diam cursus ornare nec eu quam。

Sed non vulputate purus,sed consectetur odio。 Sed non nibh fringilla, imperdiet odio nec, efficitur ex。 Suspendisse ut dignissim enim。 Maecenas felis augue,tempor sit amet sem fringilla,accumsan fringilla nibh。 Quisque posuere lacus tortor, quis malesuada magna elementum a. Nullam id purus 在 ante molestie tincidunt 中。 Morbi luctus orci eu egestas dignissim。 Sed tincidunt, libero quis scelerisque bibendum, ligula nisi gravida libero, id lacinia nulla leo in elit。

Aenean aliquam risus id consectetur sagittis。 Aliquam aliquam nisl eu augue accumsan, vel maximus lorem viverra。 Aliquam ipsum dolor、tempor et justo ac、fermentum mattis dui。 Etiam 在 posuere ligula。 Vestibulum tortor metus, viverra vitae mi non, laoreet iaculis purus。 Praesent vel semper nibh。 Curabitur 一个 congue lacus。在 et pellentesque lorem。 Morbi posuere felis non diam vulputate, non vulputate ex vehicula。 Vivamus ultricies,massa id sagittis consequat,sem mauris tincidunt nunc,eu vehicula augue quam ut mauris。

Lorem ipsum dolor sit amet,consectetur adipiscing elit。 Duis dolor neque, commodo quis leo ut, 拍卖师 tincidunt mauris。 Nunc fringilla tincidunt metus,non gravida lorem condimentum non。 Duis ornare purus nisl,位于 porta arcu eleifend eget。整数 lorem ante,porta vulputate dui ut,blandit tempor tellus。 Proin facilisis bibendum diam,坐在 amet rutrum est feugiat ut。 Mauris rhoncus convallis arcu 在调味品中。 Donec volutpat dui eu mollis vulputate。 Nunc commodo lobortis nunc 在 ultrices。吊挂在 lobortis 直径。 Suspendisse eget 前庭前庭。

Sed non vulputate purus,sed consectetur odio。 Sed non nibh fringilla, imperdiet odio nec, efficitur ex。 Suspendisse ut dignissim enim。 Maecenas felis augue,tempor sit amet sem fringilla,accumsan fringilla nibh。 Quisque posuere lacus tortor, quis malesuada magna elementum a. Nullam id purus 在 ante molestie tincidunt 中。 Morbi luctus orci eu egestas dignissim。 Sed tincidunt, libero quis scelerisque bibendum, ligula nisi gravida libero, id lacinia nulla leo in elit。


C
Charley

我意识到这个帖子已经过时了,但它在某些谷歌搜索中排名很高,所以我认为它值得更新。

您也只需获取/设置元素自身的高度:

var load_height = document.getElementById('target_box').clientHeight;
document.getElementById('target_box').style.height = load_height + 'px';

您应该在内联脚本标记中的 target_box 结束标记之后立即转储此 Javascript。