自适应的元素如何设置动画
在 css 属性为 auto 的元素不能设置动画,设置了动画也不会有效果,比如下面代码:
.dropdown { transition: 0.2s; height: 0; } .dropdown.open { /* 高度发生了改变,但是没有动画. */ height: auto; }
折叠面板大家都知道,就是希望有一个元素能够使用 CSS transition 平滑地折叠和展开,但是它的展开大小需要依赖于里面的内容。
已经设置了过渡:transition: 0.2s
,但是展开动画并没有生效。发现只有当高度为 auto 自动计算时,才会出现此问题。百分比,像素值,任何绝对单位都能正常工作。但是所有这些都需要预先设置一个特定的高度,而不是让它自然地由元素内容的大小决定。
为什么浏览器不去修复这个问题?
我们都知道“回流”的概念,重新计算所有元素的大小和位置在浏览器中非常消耗性能。如果要将一个元素transition为auto的高度,浏览器必须对该动画的每个阶段执行回流,以确定所有其他元素应该如何移动。它不能以简单的方式缓存或计算,因为展开的时候不知道具体可以展开到多大的高度。这将使浏览器必须在后台进行的数学计算变得复杂,并且可能以不明显的方式降低性能。
如果解决这个问题呢?下面有几种实现的思路给大家参考。
max-height
前文已经提到了,CSS值只能在固定单位值之间转换。但是假设我们有一个元素,它的height被设置为auto,但是它的max-height
被设置为一个固定值,比如1000px。我们不能转换高度,但我们可以转换最大高度,因为它有一个显式的值。在任何时候,元素的实际高度将是高度和最大高度的最大值决定的。所以只要max-height
的值大于auto的值,我们就可以转换max height并获得所需的效果。
这有两个关键的缺点:1、必须提前预测出高度。2、建议使用匀速动画。
transform: scaleY()
实现是这样的:我们为元素的 transform 属性设置一个转换,然后在 transform:scaleY(1)
(和transform:scaleY(0)
之间切换。这分别意味着,与开始时相同的比例(在y轴上)呈现该元素 和 以0的比例(在y轴上)呈现该元素。在这两种状态之间的转换将巧妙地 挤压 元素的自然大小和基于内容的大小。缺点呢?由于不会触发回流,因此元素周围的元素将完全不受影响。也就是说当元素展开的时候,后面的元素不会往下移动。
这种方案适合在定位的元素中使用,比如 element-ui 中的 select 组件就是基于这种方案实现的下拉展开。
JavaScript
最后就是 JS 的实现方案了,效果也是最佳的,但是实现代码有一定的难度。
如果您绝对需要平滑地过渡折叠部分,其扩展大小完全由内容决定,并且页面上的其他元素在转换时会自动伸缩,那么您可以使用一些JavaScript来实现这一点。
<div class="container"> <div class="section"> <p>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.</p> </div> <div class="section collapsible"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.</p> </div> <div class="section"> <p>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.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat.</p> </div> </div> <button>Toggle collapse</button>
JS
function collapseSection(element) { var sectionHeight = element.scrollHeight; var elementTransition = element.style.transition; element.style.transition = ''; requestAnimationFrame(function() { element.style.height = sectionHeight + 'px'; element.style.transition = elementTransition; requestAnimationFrame(function() { element.style.height = 0 + 'px'; }); }); element.setAttribute('data-collapsed', 'true'); } function expandSection(element) { var sectionHeight = element.scrollHeight; element.style.height = sectionHeight + 'px'; element.addEventListener('transitionend', function(e) { element.removeEventListener('transitionend', arguments.callee); element.style.height = null; }); element.setAttribute('data-collapsed', 'false'); } document.querySelector('#toggle-button').addEventListener('click', function(e) { var section = document.querySelector('.section.collapsible'); var isCollapsed = section.getAttribute('data-collapsed') === 'true'; if(isCollapsed) { expandSection(section) section.setAttribute('data-collapsed', 'false') } else { collapseSection(section) } });
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论