I have two div elements:
When a user scrolls div #element-A
and #header-one-target
reaches the top of the containing div the last element (#animate-hd-b
) in #element-B
should scroll to the top of the containing div with a nice animation .
Here's the code that I'm working with to start. The code below does something when the window is scrolled not the div.
$(window).scroll(function() {
var offsetTop = $('#animate-hd-b').offset().top,
outerHeight = $('#animate-hd-b').outerHeight(),
windowHeight = $(window).height(),
scrollTop = $(this).scrollTop();
console.log((offsetTop-windowHeight) , scrollTop);
if (scrollTop > (offsetTop+outerHeight-windowHeight)){
alert('you have scrolled to the top!');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="element-A" style="background: orange; overflow: auto;">
<div class="content" style="padding-bottom: 300px;">
<p>content</p>
<p>content</p>
<p>content</p>
<p>content</p>
<h1 id="header-one-target">Header One</h1>
</div>
</div>
<div id="element-B" style="background: yellow; overflow: auto;">
<div class="content" style="padding-bottom: 300px;">
<p>content</p>
<p>content</p>
<p>content</p>
<p>content</p>
<h1 id="animate-hd-b">Animate This Header</h1>
</div>
</div>
Is there a way to do this in jQuery?
This is really pretty simple. You just keep track of #header-one-target
and animate
#animate-hd-b
when #header-one-target
reaches at the top.
(function($) {
let $elementA = $('#element-A');
let $elementB = $('#element-B');
let $headerOneTarget = $('#header-one-target');
let $animateHdB = $('#animate-hd-b');
let isScrollAtTop = true;
$elementA.scroll(function() {
if (isScrollAtTop && $headerOneTarget.offset().top < 5) {
isScrollAtTop = false;
$elementB.animate({
scrollTop: $elementB.scrollTop() + $animateHdB.offset().top
});
} else if ($elementA.scrollTop() < 5) {
isScrollAtTop = true;
$elementB.animate({
scrollTop: 0
});
}
});
})(jQuery);
#element-A {
background: orange;
overflow: auto;
height: 100vh;
width: 60vw;
position: fixed;
top: 0;
left: 0;
}
#element-B {
position: fixed;
top: 0;
right: 0;
height: 100vh;
width: 40vw;
background: yellow;
overflow: auto;
}
.content {
padding: 10px;
}
.content-vh100 {
height: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="element-A">
<div class="content">
<p>Scroll</p>
<p>to</p>
<p>header</p>
<p>one</p>
<h1 id="header-one-target">Header One</h1>
<div class="content-vh100"></div>
</div>
</div>
<div id="element-B">
<div class="content">
<p>to</p>
<p>animate</p>
<p>following</p>
<p>content</p>
<h1 id="animate-hd-b">Animate This Header</h1>
<div class="content-vh100"></div>
</div>
</div>
Some conditions were added that should prevent unnecessary animations and queueing (which tends to happen when listening for scroll
and animating scrollTop
). It keeps track of the scroll direction and won't start animating when the element on the right has already reached its position.
Codepen demo
var sin = $('#element-A'),
dex = $('#element-B'),
peg = sin.scrollTop();
sin.scroll(function() {
var way = sin.scrollTop(),
rate = Math.round(sin.find('h1').position().top),
area = dex.scrollTop(),
turf = Math.round(dex.find('h1').position().top),
down = way > peg;
peg = way;
// conditions for scrolling down
if (rate < 0 && down && turf) {
dex.not(':animated').animate({scrollTop: area+turf}, 700);
}
// scrolling up
if (!down && area) {
dex.not(':animated').animate({scrollTop: 0}, 700);
}
});
body {
margin: 0;
}
body > div {
width: 50%;
height: 100vh;
float: left;
overflow: auto;
}
#element-A {
background: orange;
}
#element-B {
background: yellow;
}
.content {
padding-bottom: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="element-A">
<div class="content">
<p>content</p>
<p>content</p>
<p>content</p>
<p>content</p>
<h1 id="header-one-target">Header One</h1>
</div>
</div>
<div id="element-B">
<div class="content">
<p>content</p>
<p>content</p>
<p>content</p>
<p>content</p>
<h1 id="animate-hd-b">Animate This Header</h1>
</div>
</div>
In case the elements are differently positioned in the target environment, using position()
is a more straightforward approach than offset()
because the latter is relative to the document. The former (used here) is relative to its own parent element and should work independent of its position.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With