The Quivering Quandaries of Implementing Jquery Accordions

For a demonstration of the issue, please visit http://jsbin.com/omuqo.

Upon opening a panel by clicking on the handle, there is a slight jitter in the panels below during the animation.

In the provided demo, all panels should remain completely still as they are of equal height. However, the jitter becomes noticeable when dealing with more complex accordions with panels of varying heights and additional animations like easing.

To troubleshoot this issue, I decided to forego using the jQuery UI accordion plugin and implemented my own solution based on the advice offered here.

If the jsbin link is not functional, here is the complete code:

The HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
<head> 
<title>Sandbox</title> 
<meta http-equiv="Content-type" content="text/html; charset=utf-8" /> 
<style type="text/css" media="screen"> 
* { margin: 0; padding: 0; } 
body { background-color: #fff; font: 16px Helvetica, Arial; color: #000; } 
dt { background-color: #ccc; } 
dd { height: 100px; } 
#footer { background-color: #ff9; } 
</style> 
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script> 
</head> 
<body> 
  <dl> 
    <dt>Handle</dt> 
    <dd id="1">Content</dd> 
    <dt>Handle</dt> 
    <dd id="2">Content</dd> 
    <dt>Handle</dt> 
    <dd id="3">Content</dd> 
    <dt>Handle</dt> 
    <dd id="4">Content</dd> 
  </dl> 
  <div id="footer"> 
    Some more content 
  </div> 
</body> 
</html>

And the Javascript:

$.fn.accordion = function() {
  return this.each(function() {
    $container = $(this);

    // Hijack handles.
    $container.find("dt").each(function() {
      var $header = $(this);
      var $content = $header.next();

      $header
        .click(function() {  
          $container
            .find("dd:visible")
            .animate({ height: 0 }, { duration: 300, complete: function() {
                $(this).hide();
              }
            });
          if(!$content.is(":visible")) {
            $content
              .show()
            $content
              .animate({ height : heights[$content.attr("id")] }, { duration: 300 });
          }
          return false;
        });
    });

    // Iterate over panels, save heights, hide all.
    var heights = new Object();
    $container.find("dd").each(function() {

      $this = $(this);
      heights[$this.attr("id")] = $this.height();
      $this
        .hide()
        .css({ height : 0 });
    });
  });
};

$(document).ready(function() {
  $("dl").accordion();
});

For a smoother accordion implementation, you can refer to the website Muxtape.

Any suggestions or feedback?

Answer №1

I believe I've found a solution. The key is to sync by linking to an external transition through the step callback function. Check out a demo of the updated approach here.

This problem really had me stumped!

The javascript code:

$.fn.accordion = function() {
  return this.each(function() {
    $container = $(this);

    // Modify headers.
    $container.find("dt").each(function() {
      var $header = $(this);
      var $selected = $header.next();

    $header
        .click(function() {  
          if ($selected.is(":visible")) {
            $selected
              .animate({ height: 0 }, { duration: 300, complete: function() {
                $(this).hide();
              }
            });
          } else {
            $unselected = $container.find("dd:visible");
            $selected.show();
            var newHeight = heights[$selected.attr("id")];
            var oldHeight = heights[$unselected.attr("id")];

            $('<div>').animate({ height : 1 }, {
              duration  : 300, 
              step      : function(now) {
                var stepSelectedHeight = Math.round(newHeight * now);
                $selected.height(stepSelectedHeight);
                $unselected.height(oldHeight + Math.round((newHeight - oldHeight) * now) - Math.round(newHeight * now));
              },
              complete  : function() {
                $unselected
                  .hide()
                  .css({ height : 0 });
                }
            });
          }
          return false;
        });
    });

    // Calculate heights for all panels, hide them initially.
    var heights = new Object();
    $container.find("dd").each(function() {

      $this = $(this);
      $this.css("overflow", "hidden");
      heights[$this.attr("id")] = $this.height();
      $this
        .hide()
        .css({ height : 0 });
    });
  });
};

$(document).ready(function() {
  $("dl").accordion();
});

Answer №2

It appears that the issue stems from the lack of synchronization between two parallel animations in the accordion - one panel emerging while the other moves aside.

Seemingly, there is currently no standardized method for synchronizing animations in Jquery.

For further information, check out this link and this thread.

Quite frustrating!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to importing the Slider Component in React using Material-UI

I am trying to incorporate the Slider Component from @material-ui/core into my React project. However, when I attempt to import the Slider using this code: import Slider from '@material-ui/lab/Slider';, it gives me an error stating Module not fou ...

Adding the highcharts-more.src.js file to an Angular 2 project: A step-by-step guide

I have linked highcharts-more to the system variable: 'highcharts-more': 'node_modules/highcharts/highcharts-more.src.js' But I keep getting an error message saying: Error in dev/process/templates/detail.template.html:40:33 ORIGINAL ...

JSON data returned from an AJAX request could be utilized to populate a

Need help with displaying data in two dependent select boxes based on the selection of the first box. <?php $con=mysql_connect("localhost","root","root"); mysql_select_db("register",$con); ?> <!DOCTYPE html> <html&g ...

Leveraging the power of express, employing the await keyword, utilizing catch blocks, and utilizing the next

I am currently developing an express JS application that follows this routing style: router.post('/account/create', async function(req, res, next) { var account = await db.query(`query to check if account exists`).catch(next); if (accoun ...

Utilizing Ajax for JSON data transmission and handling with Spring MVC Controller

I am working on an ajax json POST method that looks like this. $(function () { $('#formId').submit(function (event) { event.preventDefault(); // prevents the form from being submitted var u ...

The button's onclick function is failing to save the record in the database

Hello everyone, I am facing an issue with the ONCLICK button functionality. I have written code to save a form to the database. In the image, there are 2 buttons: Save button (type="submit") Save and New button (type="button") The Save button is ...

Development and staging setups tailored specifically for a JavaScript SDK

Currently, I am working with a Javascript SDK that is available on NPM. Alongside this, I have a Vue application utilizing the SDK and it's crucial for me to test them together across various pre-production environments (such as staging). Here are the ...

The $.post method is malfunctioning

I am experiencing an issue where the onchange function is working properly, but the $.post function is not functioning as expected. Below is the HTML code snippet: <input type="checkbox" id="chk" value="3" onchange="checkradio(this.value)"/> Here ...

Revamping the Look: Refreshing Background of Div

I'm attempting to change the background image of the body element on a webpage when I hover over links with data-* attributes. It's working perfectly, but I can't seem to figure out how to create a smooth fade between the images when a link ...

Fix a typing issue with TypeScript on a coding assistant

I'm struggling with typing a helper function. I need to replace null values in an object with empty strings while preserving the key-value relationships in typescript // from { name: string | undefined url: string | null | undefined icon: ...

Determine changes in data retrieved from a JSON file using React

I've been working on a cryptocurrency app using React and a JSON API to fetch the latest data. My approach involves using fetch to load the JSON API and setInterval to refresh the app every 10 seconds. Now, I'm wondering if there's a way to ...

Utilize Vue.js to send bound data to a click event

I am currently working with a v-for loop that iterates over data fetched from an API, setting the key as the ID of each object. My goal is to create a click event that captures the v-bind:key value of the clicked element. This will allow me to locate all t ...

What is the process for aligning rows with the selected option from the drop-down menu

Alright, so here's the scenario: I have created a table along with two drop-down filters. The first filter is for selecting the Year, and it offers options like "All", "2023", "2022", and "2021". When I pick a specific year, let's say "2022", onl ...

When using React, the event.target method may unexpectedly return the innerText of a previously clicked element instead of the intended element that was

I have implemented a drop-down menu that triggers an event handler to return the selected option when it is clicked. Upon clicking on an option, I retrieve the inner text of that option using the event. The code snippet looks like this: event.target.inner ...

Spinner displayed upon task completion

Currently, I am developing a project using Spring Boot. I would like to display a spinner on my page to indicate that a task involving heavy calculations is in progress. Even though the page may take up to 5 minutes to load, my spinner only appears for t ...

Strange behavior detected in TypeScript generic function when using a class as the generic parameter

class Class { } const f0 = <T extends typeof Class> (c:T): T => { return c } const call0 = f0 (Class) //ok const f1 = <T extends typeof Class> (c:T): T => { const a = new c() return a //TS2322: Type 'Class' is not assigna ...

NodeJs encountered an issue due to the absence of defined username and data

I am facing an issue while trying to open the places.ejs file by clicking the submit button on the show.js page. Similar to how the show.ejs page opens upon clicking the submit button on the new.ejs file, I am encountering a reference error. Any assistance ...

Guide on Sending a POST Request via HTTPS in Websites

I am developing a browser extension for Chrome that requires sending a post request to a server using standard HTTP. However, this is causing a mixed content error when I'm on a website that uses HTTPS, and the browser refuses to process my request. ...

Exploring the Possibilities of Personalizing Data Tables

I have a unique requirement that I need help with: 1. On the mobile site, only 5 records should load by default with paginated data for subsequent pages. and 2. In desktop view, the default should be 10 records loaded with paginated data for subsequent ...

Failure to create an array when parsing JSON data from an Ajax request

Utilizing Ajax to call an SP that returns a string. var AjaxData = $.ajax({ type: "POST", contentType: "application/json;", url: "WebForm1.aspx/GetHeartBeatData", data: "{}", dataType ...