Guillaume Duverger - Développement & Graphisme - Blog

Vous êtes ici : Accueil > Démonstrations > JavaScript > Autres

Transition sur l'élément details en JavaScript (WAAPI animation)

Sommaire (cliquez)
  • titre
  • titre
  • titre
  • titre
  • titre
  • titre
  • titre
  • titre
  • titre

Code :

HTML




<details>
<summary>Sommaire</summary>
<ul class="contenu-details">
<li>titre</li>

...

</ul>
</details>


CSS



summary::-webkit-details-marker{display: none}	

details{

display: inline-flex

}

summary{

display: flex;
align-items: center;
padding: 4px;
column-gap: 4px;

}

details summary::before{

content:'';
border-left:calc(4px*1.5) solid transparent;
border-right:calc(4px*1.5) solid transparent;
border-top:calc(4px*2.5) solid

}


details[open] summary::before{

transform:rotate(180deg)

}




JavaScript

	
	
class Accordion {
  constructor(el) {
    
	
    this.el = el;
    

    this.summary = el.querySelector('summary');
    

    this.content = el.querySelector('.contenu-details');


    this.animation = null;
 
    this.isClosing = false;

    this.isExpanding = false;

    this.summary.addEventListener('click', (e) => this.onClick(e));
  }

  onClick(e) {
 
    e.preventDefault();
 
    this.el.style.overflow = 'hidden';

    if (this.isClosing || !this.el.open) {
      this.open();
 
    } else if (this.isExpanding || this.el.open) {
      this.shrink();
    }
  }

  shrink() {

    this.isClosing = true;
    

    const startHeight = `${this.el.offsetHeight}px`;
 
    const endHeight = `${this.summary.offsetHeight}px`;
    
 
    if (this.animation) {
      // Cancel the current animation
      this.animation.cancel();
    }
    

    this.animation = this.el.animate({
 
      height: [startHeight, endHeight]
    }, {
      duration: 400,
      easing: 'ease-out'
    });
    
  
    this.animation.onfinish = () => this.onAnimationFinish(false);
  
    this.animation.oncancel = () => this.isClosing = false;
  }

  open() {

    this.el.style.height = `${this.el.offsetHeight}px`;

    this.el.open = true;

    window.requestAnimationFrame(() => this.expand());
  }

  expand() {

    this.isExpanding = true;
 
    const startHeight = `${this.el.offsetHeight}px`;

    const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`;
    
  
    if (this.animation) {
  
      this.animation.cancel();
    }
    

    this.animation = this.el.animate({

      height: [startHeight, endHeight]
    }, {
      duration: 400,
      easing: 'ease-out'
    });
 
    this.animation.onfinish = () => this.onAnimationFinish(true);
 
    this.animation.oncancel = () => this.isExpanding = false;
  }

  onAnimationFinish(open) {

    this.el.open = open;

    this.animation = null;
 
    this.isClosing = false;
    this.isExpanding = false;
 
    this.el.style.height = this.el.style.overflow = '';
  }
}

document.querySelectorAll('details').forEach((el) => {
  new Accordion(el);
});


Vous rencontrez un problème avec cette démonstration ?

Avant de vous arracher les cheveux ou de crier au scandale, procédez à quelques simples vérifications. Si la démonstration fonctionne ici, il n'y a aucune raison pour qu'il n'en soit pas de même chez vous. De plus vous pouvez télécharger la démonstration. Si vraiment vous coincez, vous pouvez me contacter par mail (contact@guyom-design.com) et je vous aiderai si je le peux. Je ne réponds qu'aux messages respectueux.