Search code examples
javascriptdommeteor

Lock scroll as new content is added above and below


I have a meteor.js app that functions as a news feed, with threads being posted and people commenting on the threads in realtime. This means that while you are looking at a post, there will be new comments being added to posts above and below and new threads will be added above. This will push the post you are focusing on down and out of the viewport, which is never expected (unless you're already scrolled to the top).

What is the best way to update the scrolling to maintain the same visual center as new content is added?


Solution

  • You could try this approach:

    1. save the scrollTop value;
    2. prepend the content (i.e., add a new post above the one that's focused);
    3. add the height of the new content to the value saved in step 1;
    4. scroll to the new value.

    Here's an example:

    function randomString() {
      return Math.random().toString(36).substring(7);
    }
    
    $('#addAbove').on('click', function(e){
      var newDiv = $('<li class="post">' + randomString() + '</li>');
      var savedScrollTop = $('#content').scrollTop();
      $('#content').prepend(newDiv);
      $('#content').scrollTop(savedScrollTop + newDiv.height());
    });
    
    $('#addBelow').on('click', function(e){
      var newDiv = $('<li class="post">' + randomString() + '</li>');
      $('#content').append(newDiv);
    });
    #content {
      height: 100px;
      overflow-y: scroll;
    }
    .post {
      height: 40px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <ul id="content">
      <li class="post">u9tv190be29</li>
      <li class="post">dgdr8gp66rp</li>
      <li class="post">93vfntdquxr</li>
    </ul>
    <button id="addAbove">Add Above</button>
    <button id="addBelow">Add Below</button>

    Appending content below the current viewport shouldn't require adjustment.

    Here's a blog post describing a similar approach, and a similar SO question.