【发布时间】:2017-03-18 03:43:20
【问题描述】:
我有一个 DIV(一个容器元素)。
其中有一些我想淡入和淡出的元素(取决于用户滚动的方向)。这没问题。
查看嵌入式代码 sn-p 进行演示。
问题
注意演示中逐渐消失的黑色区域;我想在淡入淡出时将其保持在顶部(通过滚动一段距离)。
在此类元素的淡入和淡出期间,我希望保持父容器 (DIV) 不会(垂直)移动,直到淡入或淡出完成。这部分对我来说是个问题。
2017 年 11 月 3 日更新
我已经用一个在 Chrome 中运行良好的示例更新了我的代码(使它坚持使用负数 marginTop 拉起 div(向上滚动时)和正数 top 向下推 @987654324 @(向下滚动时)。但在 Edge 或 Firefox 中运行非常“糟糕”(滚动后触发的scroll-事件使其落后)。
我尝试过的
- 我尝试过使用
position: sticky。这首先使用position: relative,然后使用position: fixed,所以它并不能完全满足我的要求。 - 我已尝试使用“位置:固定”。当然,父容器 DIV 确实会粘在视口上。但是,因为它的高度大于视口的高度,所以它不能按照我的预期工作,例如如果用户滚动到大容器高度的 50%,则此 scrollTop 会因使用“位置:固定”而丢失。
- 我已尝试将“位置:固定”与“滚动”事件和 marginTop CSS 属性(以及“顶部”CSS 属性)结合使用。我得到了奇怪的结果。此外,“滚动”事件总是在用户滚动一定数量的像素后执行。因此,如果它能够奏效,您可能会得到一种“滞后”的体验。
- 我搜索过 jQuery 插件等,但它们也依赖于“位置:固定”,因此也受到限制。
- 我已尝试使用 ScrollMagic 并同时使用 GreenSock 的 TimelineMax 执行补间。例如,一个补间用于淡入和淡出,一个补间用于对 marginTop(再次)或 top 进行动画处理,以使用“位置:绝对”和“位置:相对”来补偿滚动距离。
- 我已经尝试捕获鼠标滚轮事件,然后以编程方式滚动(因此我可以选择不滚动)。这当然是一种选择。但我真的很想要一个滚动条。移动体验落后,因为当一个人进行程序化滚动时,一个人不能使用例如“双击”手势。
- 我已经尝试了很多东西以及这些东西的很多变体。
代码(嵌入式 sn-p)- 2017 年 11 月 3 日更新
代码在非 Chrome (!) 的浏览器中运行糟糕
var $window = $(window);
// Element which needs to fade in and out.
var $fadingblack = $("#fadingblack");
// Parent element of fading element.
var $scrollcontainer = $("#scrollcontainer");
// Last scrollTop-value.
var lastScrollTop = $window.scrollTop();
var lockForFade = false;
$window.on('scroll',
// Function which is to be called after user scrolls.
function() {
// Current scrollTop value.
var currentScrollTop = $window.scrollTop();
// Y-coordinate of element which needs to fade.
var scrollTopStart = $fadingblack.position().top;
// Y-coordinate of end of element which needs to fade.
var scrollTopEndDown = scrollTopStart + $fadingblack.height();
var scrollTopEndUp = scrollTopStart - $fadingblack.height();
// Has element which needs to fade scrolled into view.
// Does the fading itself.
function doFade($el, $parent, lastScrollTop, currentScrollTop, scrollTopStart, scrollTopEnd) {
// Curent opacity for fade; determined by scroll position.
//var currentOpacity = (currentScrollTop - scrollTopStart) / (scrollTopEnd - scrollTopStart);
var currentOpacity;
// Temporary variables for scrollTop.
var theTop;
var fadeCompleted;
function undoPushAndScroll() {
// Save the amount of pixels the parent element has been pushed down.
var savedTop = $parent.position().top;
// Then reset this 'push amount'.
$parent.css("top", 0);
// And scroll the pushed down amount of pixels back upwards.
$window.scrollTop(currentScrollTop - savedTop);
currentScrollTop -= savedTop;
}
function undoPullAndScroll() {
// Save the amount of pixels the parent element has been pulled up.
var savedTop = parseFloat($parent.css('marginTop'));
// Then reset this 'pull amount'.
$parent.css("marginTop", 0);
// And scroll the pulled up amount of pixels back downwards.
$window.scrollTop(currentScrollTop - savedTop);
currentScrollTop -= savedTop;
}
function undoPullAndDoPush() {
var savedMarginTop = parseFloat($parent.css('marginTop'));
$parent.css('marginTop', 0);
$window.scrollTop(currentScrollTop - savedMarginTop);
currentScrollTop -= savedMarginTop;
// Determine difference between start of fade (Y-value) and current scrollTop (Y-value).
var theTop = Math.abs(scrollTopStart - currentScrollTop); // + savedMarginTop;
// Push the parent element down that same difference.
$parent.css("top", theTop);
}
function undoPushAndDoPull() {
// Save the amount of pixels the parent element has been pushed down.
var savedTop = $parent.position().top;
$parent.css('top', 0);
$window.scrollTop(currentScrollTop - savedTop);
currentScrollTop -= savedTop;
// User has scrolled up.
// Determine difference between start of fade (Y-value) and current scrollTop (Y-value).
var theTop = Math.abs(scrollTopStart - currentScrollTop);
// Pull the parent element up that same difference.
$parent.css("marginTop", -theTop);
}
if (lastScrollTop < currentScrollTop) {
// User has scrolled down.
undoPullAndDoPush();
//currentOpacity = Math.abs(currentScrollTop - scrollTopStart) / $el.height();
fadePercent = Math.abs(currentScrollTop + $parent.position().top - scrollTopStart) / $el.height();
currentOpacity = fadePercent;
// Fade to current opacity immediately.
$el.fadeTo(0, currentOpacity);
// Determine if fade has completed (must scroll at least the height of the fading element).
fadeCompleted = ($parent.position().top >= $el.height());
if (fadeCompleted) {
// Then immediately set opacity to 1.
$el.fadeTo(0, 1);
// Fade has completed.
undoPushAndScroll();
lockForFade = false;
}
} else if (lastScrollTop > currentScrollTop) {
// User has scrolled up.
undoPushAndDoPull();
fadePercent = Math.abs(currentScrollTop + parseFloat($parent.css('marginTop')) - scrollTopStart) / $el.height();
currentOpacity = 1 - fadePercent;
// Fade to current opacity immediately.
$el.fadeTo(0, currentOpacity);
// Determine if fade has completed (must scroll at least the height of the fading element).
fadeCompleted = (-parseFloat($parent.css('marginTop')) >= $el.height());
if (fadeCompleted) {
// Then immediately set opacity to 0.
$el.fadeTo(0, 0);
// Fade has completed.
undoPullAndScroll();
lockForFade = false;
}
}
}
if (lastScrollTop < currentScrollTop) {
// Scrolling down in fade area.
if (!lockForFade && currentScrollTop >= scrollTopStart && lastScrollTop < scrollTopStart) {
if (parseFloat($fadingblack.css('opacity')) < 1) {
lockForFade = true;
}
}
if (lockForFade) {
doFade(
$fadingblack,
$scrollcontainer,
lastScrollTop,
currentScrollTop,
scrollTopStart,
scrollTopEndDown);
}
} else if (lastScrollTop > currentScrollTop) {
// Scrolling up in fade area.
if (!lockForFade && currentScrollTop <= scrollTopStart && lastScrollTop > scrollTopStart) {
if (parseFloat($fadingblack.css('opacity')) > 0) {
lockForFade = true;
}
}
if (lockForFade) {
console.log('dofade up');
doFade(
$fadingblack,
$scrollcontainer,
lastScrollTop,
currentScrollTop,
scrollTopStart,
scrollTopEndUp);
}
}
// Save last scrollTop-value for next scroll-event-call.
lastScrollTop = $window.scrollTop();
});
body {
background-color: whitesmoke;
}
#scrollcontainer {
position: absolute;
left: 0px;
top: 0px;
}
.red,
.blue,
.black {
position: relative;
width: 900px;
}
.red,
.blue {
height: 300px;
}
.black {
height: 600px;
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.black {
background-color: black;
}
#fadingblack {
opacity: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="scrollcontainer">
<div class="red">BEGIN</div>
<div class="blue">Fading black area is ahead...</div>
<div id="fadingblack" class="black"> </div>
<div class="blue"> </div>
<div class="red"> </div>
<div class="blue">END</div>
</div>
【问题讨论】:
-
所以你想让'fadingblack' div在它出现后就粘住,然后滚动淡入淡出,一旦淡入淡出,继续让其他div进入视野?
-
@AmericanSlime 是的,这正是我想要实现的目标。
标签: javascript jquery html css