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