1

I've recently been working on a small blog, and would like consecutive blog posts to be accessible from within an accordion (example below). This way, you can quickly skim over post titles, select one which is interesting, and read it. When finished, you can seamlessly go back to skimming without unnecessary menu navigation.

My problem is that once you're done reading a post and click on a second one, I can't get the second post to open at the top, with the title visible. Since you've already scrolled so far down to read the first post, you open 2/3 of the way through the second post. This forces the user to scroll all the way back up to the top of a post which he hasn't read yet. For some reason I can't seem to get anything to work; any guidance would be much appreciated!

UPDATE: It turns out that since I was using the slim version of jQuery, the functions I was trying to use weren't available. Now that I'm over that hurdle, everything compiles but I can't force the page to scroll to the right place.

My closest solution is this, which will scroll back up to the first card-header when a new section is opened (whereas I want the card-header which was clicked).

$(".card-header").click(function (event) {                                      
    $('html, body').animate({                                                   
        scrollTop: $(".card-header").offset().top                               
    }, 300);                                                                    
}); 

What I'm trying to do is logically equivalent to this, but this exact code doesn't scroll at all (it compiles correctly, and replacing $(this) with $(event.target) or $(event.target).parent() doesn't work either).

$(".card-header").click(function(event) {                                                                           
    $('html, body').animate({                                                   
        scrollTop: $(this).offset().top-60                     
    }, 300);  

Here's a minimal working example to reproduce my struggles:

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>


<div class="container" id="container">
  
  <div class="card">                                          
    <a class="card-header" data-toggle="collapse" href="#sec1">Title1</a>
    <div id="sec1" class="collapse" data-parent="#container">  
      <div class="card-body">                             
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
      </div>                                              
    </div>                                                  
  </div>
  
  <div class="card">                                          
    <a class="card-header" data-toggle="collapse" href="#sec2">Title2</a>
    <div id="sec2" class="collapse" data-parent="#container">  
      <div class="card-body">                             
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
      </div>                                              
    </div>                                                  
  </div>
  
</div>
Munim Munna
  • 15,455
  • 6
  • 22
  • 52
TimD1
  • 903
  • 11
  • 25

3 Answers3

5

Always scroll to the offset-top of the opening collapse element. If the closing collapse if above the opening collapse then subtract the height of the closing collapse from the offset-top of the opening collapse.

jQuery(function($){
  $('.card-header').each(function(){
    let $card_header = $(this);
    let $collapse_element = $card_header.next();
    $collapse_element.on('show.bs.collapse', function () {
      let $card_header_top = $card_header.offset().top;
      let $visible_collapse = $('.collapse.show');
      if($visible_collapse.length){
        let $visible_collapse_top = $visible_collapse.offset().top;
        if($visible_collapse_top < $card_header_top){
          $card_header_top -= $visible_collapse.height();
        }
      }
      $([document.documentElement, document.body]).animate({
        scrollTop: $card_header_top
      });
    });
  });
});
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>

<div style="height:30px"></div>
<div class="container" id="container">
  <div class="card">                                          
    <a class="card-header" data-toggle="collapse" href="#sec1">Title1</a>
    <div id="sec1" class="collapse" data-parent="#container">  
      <div class="card-body">                             
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
      </div>                                              
    </div>                                                  
  </div>
  
  <div class="card">                                          
    <a class="card-header" data-toggle="collapse" href="#sec2">Title2</a>
    <div id="sec2" class="collapse" data-parent="#container">  
      <div class="card-body">                             
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
        lots and lots of text
      </div>                                              
    </div>                                                  
  </div>
  
</div>
Munim Munna
  • 15,455
  • 6
  • 22
  • 52
  • Your jQuery function has worked great for me in Bootstrap4 over the last several months. Thank you! Unfortunately, it no longer works in Bootstrap5, even when I add the following above your code: `` – JDW Apr 07 '21 at 07:26
  • @JDW I just checked and found it working with bootstrap 5. May be it's the class name you need to match, this example uses `card-header` as header class, not `accordion-header` as shown in bootstrap website. – Munim Munna Apr 11 '21 at 16:52
  • Replacing the single instance of "card-header" with "accordian-header" only breaks the code under Bootstrap 4.x. (I'm using the web design software Blocs, which lets me choose between BS4 & BS5. Your code works fine when BS4 is used in Blocs, but switching to BS5 breaks your code, and your suggested change to "accordion-header" doesn't fix the problem. Do you have a pure JS version I can try? Even though I've loaded jQuery, I'd like to try vanilla JS to see if that works. – JDW Apr 14 '21 at 02:07
2

I added the id to the div tag from <div class="card"> to <div class="card" id="div2"> and add javascrip:

$(".card-header").click(function () {
  $('html, body').animate({
    scrollTop: $("#div2").offset().top
  }, 2000);
});

It work for me. You don't need to override everything.

quita
  • 105
  • 6
  • This does work for a single link, but I'm looking for a general solution which scrolls to the clicked header, so I won't have to copy-paste this code for each card. I've updated my question to include more details. – TimD1 Feb 25 '19 at 01:02
-1

Have use in event

 $(document).ready(function () {
     $("html, body").animate({
            scrollTop: 0  
     }, 600);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

Have fun

Tran Anh Hien
  • 499
  • 6
  • 11