繁体   English   中英

如何从滚动中阻止DIV大于视口?

[英]How to stop DIV larger than viewport from scrolling?

我有一个DIV(容器元素)。

其中有一些我希望淡入和淡出的元素(取决于用户滚动的方向)。 这没问题。

有关演示,请参阅嵌入式代码段。

问题

注意演示中淡化的黑色区域; 我希望在褪色的同时将它保持在顶部(通过滚动一段距离)。

在这些元素的淡入和淡出期间,我希望保持父容器(DIV)不移动(垂直)直到淡入或淡出完成。 而这部分对我来说是一个问题。

更新11-03-2017

我已经用一个例子更新了我的代码,它似乎在Chrome中运行正常(使用负marginTop来提升div (向上滚动时)和正向top用于向下推div (向下滚动时)。但是在运行时非常例如Edge或Firefox中的“糟糕”( scroll后触发的事件使其落后)。

我试过了什么

  • 我尝试过使用position: sticky 这使用position: relative第一,然后position: fixed所以它不是我想要的。
  • 我尝试过使用'position:fixed'。 当然,父容器DIV确实粘在视口上。 但是,因为它的高度大于视口的高度,所以它不能按照我的预期方式工作,例如,如果用户滚动到大容器高度的50%,则使用“position:fixed”将此scrollTop丢失。
  • 我尝试将'position:fixed'与'scroll'事件和marginTop CSS-property(以及'top'CSS属性)结合使用。 我得到了奇怪的结果。 此外,在用户滚动一定量的像素之后总是执行“滚动”事件。 因此,如果它能够工作,那么可能会遇到“滞后”的经历。
  • 我已经搜索了jQuery插件等,但它们也依赖于“position:fixed”,因此也受到限制。
  • 我尝试过ScrollMagic并使用GreenSock的TimelineMax同时执行补间。 例如淡入淡出和淡出的一个补间和一个补间利用marginTop(再次)或顶部的补间以补偿'position:absolute'和'position:relative'的滚动距离。
  • 我试过捕获鼠标滚轮事件然后滚动programmaticaly(所以我可以选择不滚动)。 这当然是一种选择。 但我真的很喜欢滚动条。 移动体验滞后,因为当编程滚动时,人们无法使用例如“双击”手势。
  • 我尝试了很多东西,并尝试了很多变化。

代码(嵌入代码段) - 已更新11-03-2017

在非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">&nbsp;</div> <div class="blue">&nbsp;</div> <div class="red">&nbsp;</div> <div class="blue">END</div> </div> 

可能没有办法真正 - 以一种更自然的方式 - 防止使用position: fixeddiv position: fixed - 甚至position: sticky (它首先使用相对定位, 然后在固定定位时使用相对定位) - 并且具有更大的您希望它在特定点滚动时的大小比视口大。

仍然,我的问题的目标(停止滚动淡出一些div元素)我可以用一些代码行回答自己。 总结:使用div marginTop来拉出使用固定定位的div div子元素。

我确实至少有一个与此代码相关的其他问题(可能是两个)(但不是防止滚动)。 但这是我可以提出的其他问题,作为新问题。

我现在会接受我自己的答案。 如果有人对这个问题有一个更好或更“自然”的想法 - 我有点怀疑 - 我会高兴地改变我对这个答案的接受。

 var $window = $(window); var $document = $(document); // Element which needs to fade in and out. var $fadingblack = $("#fadingblack"); var $scrolldistract = $("#scrolldistract"); var $scrollsviascrolldistract = $("#scrollsviascrolldistract"); // Pulls up the child divs of #scrollsviascrolldistract, under it. var $puller = $("#puller"); // Start of fading area (Y-value). var scrollTopStart = $fadingblack.position().top; // And of course the Y-value of the end of the fading area. var scrollTopEnd = scrollTopStart + $fadingblack.height(); // Maximum scrollTop-value (when scrollbar is at 100%). var lastScrollTop = $document.height() - $window.height(); // Amount of scrolled pixels (vertically) including amount scrolled while // the fading element is fading. var scrollAmountWithFadeAmount = $document.height + $fadingblack.height(); // Setting height does not quite work for an empty div, // so we are using some padding. $scrolldistract.css("paddingTop", scrollAmountWithFadeAmount); // Percentage of which we have scrolled (1 = 100%). var currentScrollTopP; // Current scrollTop value. var realCurY; $(function() { // Off you go code... function doScrollOrFade() { currentScrollTopP = Math.ceil($window.scrollTop() / lastScrollTop * 100) / 100; realCurY = currentScrollTopP * lastScrollTop; if (realCurY >= scrollTopStart && realCurY <= scrollTopEnd) { // Current realCurY dictates we are in fade area. // So scroll the fading area into view at top of browser viewport. $puller.css("marginTop", -scrollTopStart); // Determine opacity percentage. var fadePercent = (realCurY - scrollTopStart) / (scrollTopEnd - scrollTopStart); // Fade to current opacity immediately. $fadingblack.fadeTo(0, fadePercent); } else { // We are outside of the fading area and in scroll-mode. if (realCurY < scrollTopStart) { // We are somewhere before the fading area, so set opacity to 0. $fadingblack.fadeTo(0, 0); } else { // We are somewhere after the fading area, so set opacity to 1. $fadingblack.fadeTo(0, 1); } if (realCurY > scrollTopEnd) { // We have passed the fading area. So we have an amount // of pixels we wasted on the opacity changes. // Correct it here. $puller.css("marginTop", -realCurY + $fadingblack.height()); } else { $puller.css("marginTop", -realCurY); } } window.requestAnimationFrame(doScrollOrFade); } window.requestAnimationFrame(doScrollOrFade); $window.on('resize orientationchange', function(e) { // On resize or orientation change recalculate some stuff. lastScrollTop = $document.height() - $window.height(); scrollAmountWithFadeAmount = $document.height + $fadingblack.height(); $scrolldistract.css("paddingTop", scrollAmountWithFadeAmount); window.requestAnimationFrame(doScrollOrFade); }); }); 
 body { background-color: whitesmoke; } #scrollsviascrolldistract { position: fixed; left: 0px; top: 0px; width: 100%; } #scrolldistract { position: absolute; left: 0px; top: 0px; width: 100%; padding-top: 2100px; height: 0px; } #puller { position: relative; margin-top: 0px; left: 0px; top: 0px; } img { display: block; } .black, .red, .blue { border: solid 1px yellow; font-size: 32pt; position: relative; width: 100%; height: 300px; } .red { background-color: red; } .blue { background-color: blue; } .black { background-color: black; } 
 <!-- For mobile support use viewport meta-tag inside <head>: <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=yes"> --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="scrolldistract"></div> <div id="scrollsviascrolldistract"> <!-- For pulling up the red, blue and fading area --> <div id="puller"></div> <div class="red">BEGIN</div> <div class="blue">Fading black area is ahead...</div> <div id="fadingblack" class="black">&nbsp;</div> <div class="blue">&nbsp;</div> <div class="red">&nbsp;</div> <div class="blue">END</div> </div> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM