Lenis平滑滚动在Firefox中元素下拉动画后无法滚动到底部
问题解决:Firefox中Lenis平滑滚动容器在元素动画后无法滚动到底部
补充说明:该功能在Chrome和Edge中正常运行。Windows平台最新版Safari(5.1.7)因不支持箭头函数(=>)且不再适配Windows 10更新,无法运行,但新版本Safari可能正常。本文问题针对Firefox!
问题描述
启用Lenis平滑滚动的.page容器内,有一个通过负margin-top隐藏的.filters-nav元素和触发按钮。点击按钮后,元素展开/收起,但容器无法滚动到底部,手动调整窗口大小后恢复正常。需要实现无需手动调整窗口,滚动自动恢复。
现有代码
Lenis初始化代码
const pageElements = document.querySelectorAll('.page'); pageElements.forEach((pageElement) => { const lenis = new Lenis({ wrapper: pageElement, content: pageElement, duration: 1.2, easing: function(t){return (t === 1 ? 1 : 1 - Math.pow(2, -10 * t))}, direction: 'vertical', gestureDirection: 'vertical', smooth: true, smoothWheel: true, smoothTouch: false, touchMultiplier: 2, autoResize: true, }); function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); });
按钮/元素动画代码
var $filtersnav = $('.filters-nav'); var filtersnavHeight = $filtersnav.height() + 30; var clickCounter = 0; $filtersnav.css('margin-top', -1 * filtersnavHeight); $('.filters-bttn').click(function() { var $filtersnav = $('.filters-nav'); var filtersnavHeight = $filtersnav.height() + 30; if (clickCounter % 2 === 0) { $filtersnav.css('margin-top', '0'); } else { $filtersnav.css('margin-top', -1 * filtersnavHeight); } clickCounter++; });
CSS代码
.page { position: relative; z-index: 5; overflow-y: auto; scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* Internet Explorer 10+ */ width: 100%; height: 100vh; pointer-events: auto; background-color: #f7f7f7; -webkit-transition: -webkit-transform 0.45s, opacity 0.45s; transition: transform 0.45s, opacity 0.45s; -webkit-transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1); transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1); } .filters-bttn { position:relative; display:block; height:50px; z-index:2; } .filters-nav { position:relative; display:block; -webkit-transition: all 0.65s ease; transition: all 0.65s ease; z-index:1; }
解决方案
问题根源是Lenis未感知到容器内容高度变化,手动调窗口触发resize后才重新计算滚动范围。只需在元素动画完成后,手动调用Lenis的resize()方法即可。
修改后的代码
- 存储Lenis实例:将每个Lenis实例绑定到对应
.page元素,方便后续调用
const pageElements = document.querySelectorAll('.page'); pageElements.forEach((pageElement) => { const lenis = new Lenis({ wrapper: pageElement, content: pageElement, duration: 1.2, easing: function(t){return (t === 1 ? 1 : 1 - Math.pow(2, -10 * t))}, direction: 'vertical', gestureDirection: 'vertical', smooth: true, smoothWheel: true, smoothTouch: false, touchMultiplier: 2, autoResize: true, }); // 将实例绑定到元素上 pageElement.lenisInstance = lenis; function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); });
- 监听动画结束并触发resize:在
.filters-nav过渡动画结束后,调用对应Lenis实例的resize()
var $filtersnav = $('.filters-nav'); var filtersnavHeight = $filtersnav.height() + 30; var clickCounter = 0; $filtersnav.css('margin-top', -1 * filtersnavHeight); // 监听过渡结束事件 $filtersnav.on('transitionend', function() { // 找到当前元素所在的.page容器 const pageElement = $(this).closest('.page')[0]; // 调用Lenis实例的resize方法,重新计算滚动范围 if (pageElement.lenisInstance) { pageElement.lenisInstance.resize(); } }); $('.filters-bttn').click(function() { var $filtersnav = $('.filters-nav'); var filtersnavHeight = $filtersnav.height() + 30; if (clickCounter % 2 === 0) { $filtersnav.css('margin-top', '0'); } else { $filtersnav.css('margin-top', -1 * filtersnavHeight); } clickCounter++; });
原理说明
- 绑定Lenis实例到
.page元素,确保能精准找到当前容器对应的平滑滚动实例 - 监听
transitionend事件,保证元素动画完全结束后再更新尺寸,此时容器内容高度已稳定 - 调用
lenis.resize()手动触发Lenis重新计算容器滚动范围,替代手动调整窗口的效果,让滚动恢复正常
内容的提问来源于stack exchange,提问作者Igor Laszlo
相关产品推荐
相关产品推荐

