8

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?

13
  • Yep, you capture the distance of the h1 from the top of it's container, and subtract the vertical scroll offset of the parent. When those reach <= 0, then you perform an animate on the second one, setting the second content's scrollTop to the distance of it's h1 from the top of it's container Commented Mar 21, 2019 at 20:43
  • @Taplar Do you have a code example? Commented Mar 21, 2019 at 22:00
  • 1
    No, because that would require me to write up a full solution, while your question has not shown an attempt to solve this on your own. This is why I've included the first comment to give you a push towards the direction you should go in. Commented Mar 21, 2019 at 22:01
  • @Taplar Please see my code example Commented Mar 22, 2019 at 16:42
  • 1
    Only looked into it shortly before, Jimmy. I've amended it now and posted it as an answer. Commented Mar 25, 2019 at 2:51

2 Answers 2

4

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>

Sign up to request clarification or add additional context in comments.

8 Comments

Looks like it builds up a queue of animations when using a browser with smooth scrolling, which makes the element on the right to get stuck.
Customize the if-condition to your needs, keep flags to avoid queue buildup.
@MunimMunna Very helpful. Is there animation be called more than once? For example if I scroll down the header reaches the top. The animation activates. But if I Scroll back up, and scroll down again The header does not animate. I know this is silly on my part but I'm just curious why it doesn't animate (scroll to the top ) again.
@Jimmy I didn't get your query, the header does not animate because it's already at the top, isn't it? if you want it to go back to original position when scrolled to the top, just add another if-block.
Check updated answer, is this what you are looking for?
|
3
+50

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.

6 Comments

This is helpful I'm curious. Is there anyway to reverse the animation when the user scrolls the opposite direction? I only ask because the animation is called only once when I scroll.
No problem, I've added it to the demo. Let me know if that is the intented behaviour, I'll only edit the answer if it is (and maybe you have more feedback before that).
I'm curious. What if I had multiple headers on the left <h1 id="header-one-target">Header One</h1> , <h1 id="header-two-target">Header Two</h1> and based off of the position of the headers I could animate the "Animate Header on the right? Any suggestions? Would I need to create multiple conditions?
Maybe you could be more specific what should happen to the element on the right... but here is an example where the second target changes the its text color.
I've worked on a more elaborate example but I'll have to give it another review to see if there aren't any glitches (I like to be thorough).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.