¿Cómo aplicar los cambios de CSS en order?

A veces me encuentro con casos en los que quiero aplicar varios cambios al CSS en sucesión inmediata, asegurándome de que cada uno esté registrado por el procesador.

Aquí hay un ejemplo simplificado

La altura del elemento es automática, por lo que no se puede hacer la transición desde. Así que me gustaría establecer la altura de los elementos a la altura calculada actual y luego cambiar inmediatamente la class para iniciar la transición. Si eso sucede en la siguiente línea de código, el renderizador css no tiene time para reactjsr al primer cambio y es como si solo se hubiera cambiado la class -> sin transición.

var foo = $(".foo"); foo[0].addEventListener("click", function(ev){ foo.css({"height":foo.height()+"px"}); foo.addClass("active"); }); //this doesn't work, foo.css…' is ignonetworking. 

Podemos retrasar al paso de time animable más pequeño con window.requestAnimationFrame() , sin embargo, debido a las diferencias del browser, estos ya necesitan dos llamadas anidadas para admitir Firefox.

 var dan = $(".dan"); dan[0].addEventListener("click", function(ev){ window.requestAnimationFrame(function(){ dan.css({"height":dan.height()+"px"}); window.requestAnimationFrame(function(){ dan.addClass("active"); }); }); }); //this does work (afai can tell), but feels overdone with all that nesting. 

Técnicamente, este código funciona. Me pregunto si esta es realmente la mejor manera de encadenar cambios de CSS como este o si hay otros methods.

Puede usar setTimeout aquí para asegurarse de que el cambio de class siempre ocurra después de calcular la height del div .

Ejemplo:

 var foo = document.getElementsByClassName('foo')[0]; var bar = document.getElementsByClassName('bar')[0]; var dan = document.getElementsByClassName('dan')[0]; function fooFunction(element) { element.style.height = element.clientHeight + 'px'; setTimeout(function(){ element.classList.add('active'); element.removeAttribute('style'); },10); } foo.addEventListener('click',function(){fooFunction(foo);},false); bar.addEventListener('click',function(){fooFunction(bar);},false); dan.addEventListener('click',function(){fooFunction(dan);},false); 
 .foo, .bar, .dan{ width:20%; display: inline-block; overflow: hidden; vertical-align:top; transition: height 1s ease-out; } .active { height:50px; } .foo { background:rgb(150, 100, 100); } .bar { background:rgb(150, 150, 100); } .dan { background:rgb(100, 150, 100); } 
 <div class="foo"> <p>Works.</p> <p>Another paragraph.</p> <p>Third paragraph. This one is even longer. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quibusdam, fugiat facere? Animi, odit et tempore debitis modi quae eaque, libero, dolores magni, voluptas tenetur tempora quidem alias ut praesentium sed.</p> </div> <div class="bar"> <p>Works.</p> <p>Another paragraph.</p> <p>Third paragraph. This one is even longer. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quibusdam, fugiat facere? Animi, odit et tempore debitis modi quae eaque, libero, dolores magni, voluptas tenetur tempora quidem alias ut praesentium sed.</p> <p>Fourth paragraph. This one is even longer. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quibusdam, fugiat facere? Animi, odit et tempore debitis modi quae eaque, libero, dolores magni, voluptas tenetur tempora quidem alias ut praesentium sed.</p> </div> <div class="dan"> <p>Works.</p> <p>Another paragraph.</p> <p>Third paragraph. This one is even longer. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quibusdam, fugiat facere? Animi, odit et tempore debitis modi quae eaque, libero, dolores magni, voluptas tenetur tempora quidem alias ut praesentium sed.</p> <p>Fourth paragraph. This one is even longer. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quibusdam, fugiat facere? Animi, odit et tempore debitis modi quae eaque, libero, dolores magni, voluptas tenetur tempora quidem alias ut praesentium sed.</p> <p>Fifth paragraph. This one is even longer. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quibusdam, fugiat facere? Animi, odit et tempore debitis modi quae eaque, libero, dolores magni, voluptas tenetur tempora quidem alias ut praesentium sed.</p> </div> 

Si no conoce la altura de los elementos de destino antes del evento de clic, simplemente verifique que el DOM esté listo y configure cada uno de los elementos de destino según su altura. de esta manera, cuando click un elemento objective: * la animation funcionará porque la altura del elemento ya está configurada. * habrá un command less para ejecutar en el evento click.

si ya trabaja con jQuery, puede usarlo en todo momento:

 $(document).ready(function(){ // use document ready so we can get the target elements height after they finished to load. var $tran = $('.transition'); // get "transition" class. instead of using different class name for each element, i use unique class for the animation part, the change needs to be on the HTML and CSS too of course, you will see it in the example. $tran.each(function(){ // run each loop so we can get each of the elements that have the class "transition", this is important when the elements height different from each other. var height = $(this).height(); // get the height of the current element in the loop. $(this).height(height); // set the height of the current element in the loop. }); $tran.click(function(){ // set jQuery click event $(this).addClass('active'); // add the "active" class }); }); 

vainilla:

 document.addEventListener('DOMContentLoaded', function(){ // use DOMContentLoaded so we can get the target elements height after they finished to load. var tran = document.getElementsByClassName('transition'); // get "transition" class. for ( let i = 0; i <= tran.length-1; i++ ){ // run for loop so we can get each of the elements that have the class "transition", this is important when the elements height different from each other. let height = tran[i].clientHeight; // get the height of the current element in the loop. tran[i].style.height = height + 'px'; // set the height of the current element in the loop. tran[i].addEventListener("click", function(ev){ // set click event this.className = this.className + " active"; // add the "active" class }); } }); 

cada uno de los elementos objective obtuvo la class de transición:

 <div class="foo transition"> ... <div class="bar transition"> ... <div class="dan transition"> ... 

la parte de transición se mueve a su propia class para que pueda eliminar la class del HTML más adelante si decide dejarla caer o usarla para otros elementos. ya no está en la class "activa", por lo que afecta a los elementos sin connection al evento click, de esta forma puedes usar por ejemplo toggleClass() lugar de addClass() y obtendrás una animation de "apertura" onclick de nuevo en los elementos:

 .foo, .bar, .dan { width: 20%; display: inline-block; overflow: hidden; vertical-align: top; } .transition { -webkit-transition: height 1000ms; transition: height 1000ms; } .active { height: 50px !important; } 

ejemplo en vivo: https://jsfiddle.net/84joouov/ * en el ejemplo te dejo elegir usar JS puro a jQuery estableciendo la variable "use_jquery" en verdadero o falso.