简体   繁体   English

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

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

I have a DIV (a container element). 我有一个DIV(容器元素)。

In it are some elements I would like to fade-in and fade-out (depending on which direction users are scrolling). 其中有一些我希望淡入和淡出的元素(取决于用户滚动的方向)。 This is no problem. 这没问题。

See embedded code snippet for demo. 有关演示,请参阅嵌入式代码段。

Problem 问题

Note the fading black area in the demo; 注意演示中淡化的黑色区域; I would like to keep this at the top while fading it (by scrolling some distance). 我希望在褪色的同时将它保持在顶部(通过滚动一段距离)。

During fade-in and fade-out of such elements I would like to keep the parent container (DIV) from moving (vertically) until the fade-ins or fade-outs have completed. 在这些元素的淡入和淡出期间,我希望保持父容器(DIV)不移动(垂直)直到淡入或淡出完成。 And this part is what forms a problem for me. 而这部分对我来说是一个问题。

Update 11-03-2017 更新11-03-2017

I have updated my code with an example which seems to run okay in Chrome (makes it stick using negative marginTop for pulling up a div (when scrolling up) and positive top for pushing down a div (when scrolling down). But in runs very 'crappy' in eg Edge or Firefox ( scroll -event fired after scrolling makes it lag behind). 我已经用一个例子更新了我的代码,它似乎在Chrome中运行正常(使用负marginTop来提升div (向上滚动时)和正向top用于向下推div (向下滚动时)。但是在运行时非常例如Edge或Firefox中的“糟糕”( scroll后触发的事件使其落后)。

What I have tried 我试过了什么

  • I have tried using position: sticky . 我尝试过使用position: sticky This uses position: relative first, then position: fixed so it does not quite do what I want. 这使用position: relative第一,然后position: fixed所以它不是我想要的。
  • I have tried using 'position: fixed'. 我尝试过使用'position:fixed'。 Of course then the parent container DIV does stick to the viewport. 当然,父容器DIV确实粘在视口上。 But then, because its height is larger than that of the viewport it does not work the way I intended, eg if a user scrolls to 50% of the height of the large container, this scrollTop gets lost by using 'position: fixed'. 但是,因为它的高度大于视口的高度,所以它不能按照我的预期方式工作,例如,如果用户滚动到大容器高度的50%,则使用“position:fixed”将此scrollTop丢失。
  • I have tried using 'position: fixed' in combination with 'scroll' event and marginTop CSS-property (and also just the 'top' CSS property). 我尝试将'position:fixed'与'scroll'事件和marginTop CSS-property(以及'top'CSS属性)结合使用。 I get weird results with this. 我得到了奇怪的结果。 Also the 'scroll' event is always executed after the user scrolls a certain amount of pixels. 此外,在用户滚动一定量的像素之后总是执行“滚动”事件。 So if it would work one would probably get a 'laggy' experience. 因此,如果它能够工作,那么可能会遇到“滞后”的经历。
  • I have searched for jQuery plugins and such but they too rely on 'position: fixed' and are thus also limited. 我已经搜索了jQuery插件等,但它们也依赖于“position:fixed”,因此也受到限制。
  • I have tried ScrollMagic and simultaneously executed tweens using GreenSock's TimelineMax. 我尝试过ScrollMagic并使用GreenSock的TimelineMax同时执行补间。 Such as one tween for the fade-in and fade-out and one tween which animates the marginTop (again) or top again to compensate for the scrolled distance with 'position: absolute' and 'position: relative' too. 例如淡入淡出和淡出的一个补间和一个补间利用marginTop(再次)或顶部的补间以补偿'position:absolute'和'position:relative'的滚动距离。
  • I have tried just capturing mousewheel events and scroll programmaticaly then (so I can choose to not scroll). 我试过捕获鼠标滚轮事件然后滚动programmaticaly(所以我可以选择不滚动)。 It is an option of course. 这当然是一种选择。 But I would really like a scrollbar. 但我真的很喜欢滚动条。 The mobile experience lags behind because when one does programmatic scrolling one cannot use eg 'double tap' gesture. 移动体验滞后,因为当编程滚动时,人们无法使用例如“双击”手势。
  • I have tried a lot of things and lots of variations of those things. 我尝试了很多东西,并尝试了很多变化。

Code (embedded snippet) - updated 11-03-2017 代码(嵌入代码段) - 已更新11-03-2017

Code works crappy in browsers which aren't Chrome (!) 在非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> 

There is probably no way to really - in a more natural kind of way - prevent a div which uses position: fixed - or even position: sticky (which uses relative positioning at first and later when it sticks fixed positioning) - and has a larger size than viewport from scrolling when you want it to at a certain point. 可能没有办法真正 - 以一种更自然的方式 - 防止使用position: fixeddiv position: fixed - 甚至position: sticky (它首先使用相对定位, 然后在固定定位时使用相对定位) - 并且具有更大的您希望它在特定点滚动时的大小比视口大。

Still, the goal of my question (stop scrolling to fade some div elements) I can answer myself with some lines of code. 仍然,我的问题的目标(停止滚动淡出一些div元素)我可以用一些代码行回答自己。 In summary: use marginTop of a div to pull up some div child elements of a div which uses fixed positioning. 总结:使用div marginTop来拉出使用固定定位的div div子元素。

I do have at least one other question (maybe two) relating to this code (but not to the prevention of scrolling). 我确实至少有一个与此代码相关的其他问题(可能是两个)(但不是防止滚动)。 But that are other questions which I can ask as new questions. 但这是我可以提出的其他问题,作为新问题。

I will accept my own answer for now. 我现在会接受我自己的答案。 If someone has a better or more 'natural' idea concerning this question - which I somehow doubt - I will happily change my acceptance to that answer. 如果有人对这个问题有一个更好或更“自然”的想法 - 我有点怀疑 - 我会高兴地改变我对这个答案的接受。

 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