1

I have a list of cards that when clicked should show a summary.

When a new summary is displayed the summary container animates to a position aligned (top) with its associated card.

Because the summaries content can vary I want to also animate the height of the summary container, but whatever I try* the container height just 'snaps' without any kind of transition.

*Attempt 1

$('.summary > div').css({'height':0,'overflow':'hidden'});
$('.summary > div[data-content="'+ activeIndex +'"]').css({'height':'initial'});

*Attempt 2

$('.summary > div').fadeOut();
$('.summary > div[data-content="'+ activeIndex +'"]').fadeIn();

*Attempt 3

$('.summary > div').animate({'height':0, 'overflow':'hidden'});
$('.summary > div[data-content="'+ activeIndex +'"]').animate({height:'initial', 'overflow':'visible'},200);

In my CSS I am using transition: all 2s ease; to try and animate both margin-top and height.

I've setup a test case below, which is best run 'full page':

$(document).ready(function() {
  alignSummary = function() {
    // Animate the summary panel
    $('.summary').css({
      'margin-top': ($('.card.is-active')[0].offsetTop - 50)
    })

    // Show/hide the relevant summary content
    var activeIndex = $('.card.is-active').index();
    $('.summary > div').hide();
    $('.summary > div[data-content="' + activeIndex + '"]').show();
  }
  alignSummary();
});

$('.card').on('click', function() {
  // Do this if a card with a greater index is clicked
  if ($(this).closest('.card').index() > $('.card.is-active').index()) {
    // Scroll the window to the top of the active card
    $([document.documentElement, document.body]).animate({
      scrollTop: ($(this).closest('.card').offset().top - 20)
    }, 800);
  }

  // Swap the active class to the card clicked
  $(this).closest('.card').siblings().removeClass('is-active');
  $(this).closest('.card').addClass('is-active');
  alignSummary();
})
body {
  margin: 0;
}

.container {
  padding: 25px;
  overflow: hidden;
}

.card,
.summary {
  margin-bottom: 1rem;
  border: 1px solid #e3e3e3;
  padding: 1rem;
  border-radius: 4px;
  width: 49%;
}

.card.is-active {
  border-color: red;
}

.card {
  float: left;
}

.summary {
  float: right;
  width: 40%;
  transition: all 2s ease;
}

div[data-content="1"] {
  height: 500px;
}

div[data-content="2"] {
  height: 100px;
}

div[data-content="3"] {
  height: 400px;
}

div[data-content="4"] {
  height: 1200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
  <div class="summary">
    <div data-content="1">
      <h2>Variable height summary 1</h2>
      <p>Some content: 500px height</p>
    </div>
    <div data-content="2">
      <h2>Variable height summary 2</h2>
      <p>Some content: 100px height</p>
    </div>
    <div data-content="3">
      <h2>Variable height summary 3</h2>
      <p>Some content: 400px height</p>
    </div>
    <div data-content="4">
      <h2>Variable height summary 4</h2>
      <p>Some content: 1200px height</p>
    </div>
  </div>
  <div class="card is-active">Click me</div>
  <div class="card">Click me</div>
  <div class="card">Click me</div>
  <div class="card">Click me</div>


</div>
kalehmann
  • 4,821
  • 6
  • 26
  • 36
dom_ahdigital
  • 1,651
  • 18
  • 37

1 Answers1

0

You can use jquery's .slideUp/.slideDown instead of .hide/.show to animate height.

$(document).ready(function() {
  alignSummary = function() {
    // Animate the summary panel
    $('.summary').css({
      'margin-top': ($('.card.is-active')[0].offsetTop - 50)
    })

    // Show/hide the relevant summary content
    var activeIndex = $('.card.is-active').index();
    $('.summary > div').slideUp(1000);
    $('.summary > div[data-content="' + activeIndex + '"]').slideDown(1000);
  }
  alignSummary();
});

$('.card').on('click', function() {
  // Do this if a card with a greater index is clicked
  if ($(this).closest('.card').index() > $('.card.is-active').index()) {
    // Scroll the window to the top of the active card
    $([document.documentElement, document.body]).animate({
      scrollTop: ($(this).closest('.card').offset().top - 20)
    }, 800);
  }

  // Swap the active class to the card clicked
  $(this).closest('.card').siblings().removeClass('is-active');
  $(this).closest('.card').addClass('is-active');
  alignSummary();
})
body {
  margin: 0;
}

.container {
  padding: 25px;
  overflow: hidden;
}

.card,
.summary {
  margin-bottom: 1rem;
  border: 1px solid #e3e3e3;
  padding: 1rem;
  border-radius: 4px;
  width: 49%;
}

.card.is-active {
  border-color: red;
}

.card {
  float: left;
}

.summary {
  float: right;
  width: 40%;
  transition: all 2s ease;
}

div[data-content="1"] {
  height: 500px;
}

div[data-content="2"] {
  height: 100px;
}

div[data-content="3"] {
  height: 400px;
}

div[data-content="4"] {
  height: 1200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
  <div class="summary">
    <div data-content="1">
      <h2>Variable height summary 1</h2>
      <p>Some content: 500px height</p>
    </div>
    <div data-content="2">
      <h2>Variable height summary 2</h2>
      <p>Some content: 100px height</p>
    </div>
    <div data-content="3">
      <h2>Variable height summary 3</h2>
      <p>Some content: 400px height</p>
    </div>
    <div data-content="4">
      <h2>Variable height summary 4</h2>
      <p>Some content: 1200px height</p>
    </div>
  </div>
  <div class="card is-active">Click me</div>
  <div class="card">Click me</div>
  <div class="card">Click me</div>
  <div class="card">Click me</div>


</div>
Chris Li
  • 2,628
  • 1
  • 8
  • 23