0
votes

I have written a snippet of code to create an accordion that you can see the code here.
There is some HTML code:

<div class="accordion_holder">
  <div class="accordion_item">
    <div class="title" onclick="toggle_accordion(this);">
      title 1 here
    </div>
    <div class="content">
      content here
    </div>
  </div>
  <div class="accordion_item">
    <div class="title" onclick="toggle_accordion(this);">
      title 2 here
    </div>
    <div class="content">
      content 2 here
    </div>
  </div>
</div>

And I have bellow CSS to simulate accordion transition:

.accordion_holder .content {
    height: 0px;
    overflow: hidden;
    -webkit-transition: height 0.5s linear;
    -moz-transition: height 0.5s linear;
    -ms-transition: height 0.5s linear;
    -o-transition: height 0.5s linear;
    transition: height 0.5s linear;
}

And I am setting the height of content to 0px or it's offsetHeight using this snippet of JavaScript code:

function toggle_accordion(clicked_element) {
  var father = closest_parent(clicked_element, 'accordion_item');
  console.log(father);
  var accordion_content = father.getElementsByClassName("content")[0];
  var destination = 0;

  var current_height = accordion_content.offsetHeight;

  if (current_height == 0)
  {
    accordion_content.style.height = "auto";
    destination = accordion_content.offsetHeight;

    accordion_content.style.height = "0px";
  }
  console.log("destination is:", destination);
  accordion_content.style.height = destination+"px";
}

/************************************
 ** Find Closest Parent with Class **
 ***********************************/
function closest_parent (current_element, class_name) {
    var parent = current_element.parentElement;
    if (parent) {
        if (parent.className.indexOf(class_name) >= 0)
        {
            //We found requested parent
            return parent;
        }
        else
        {
            return closest_parent (parent, class_name);
        }
    }
    else
    {
        return false;
    }
}

It's working correctly to set the height of content element. when it is closing (set the height of Content element to 0px), it will move smoothly and transition effect is working. but when it is opening (set the height of Content element to offsetHeight), Transition won't work.
Can you please guide me what is wrong?

1

1 Answers

2
votes

It's because you're setting the height to auto and then trying to get its offsetHeight.

Getting the offsetHeight triggers a reflow, so it's already going to layout the page and try to make a transition to height: auto; Since transitions to height: auto don't work, it's going to jump straight to the target height. Then, when you set the element's height to the value you got from offsetHeight, the element already has that height, so there will be no transition.

Two ways you could fix that:

A more hacky way is to turn the reflow triggered by offsetHeight to your favor: just try to get the value again after setting the height back to 0, triggering the reflow again:

if (current_height == 0)
  {
    accordion_content.style.height = "auto";
    destination = accordion_content.offsetHeight;

    accordion_content.style.height = "0px";
    // Here is the trick:
    accordion_content.offsetHeight // triggers a reflow
  }

Another way is to store the height of the contents of the accordion elements beforehand, so you just transition to that value. That can be tricky, especially if the contents of the accordion can change, but it's less dependent on esoteric browser behaviour.