2013-03-03 6 views
7

Sono sorpreso dal fatto che una regola di transizione CSS3 applicata tramite jQuery dopo una modifica di proprietà CSS basata su jQuery anima effettivamente questa modifica di proprietà. Dare un'occhiata a http://jsfiddle.net/zwatf/3/:esempio JavaScript/jQuery molto semplice: ordine di valutazione imprevisto delle istruzioni

Inizialmente, un div è disegnato da due classi e ha una certa altezza (200px) a causa delle proprietà CSS predefinite di queste due classi. L'altezza viene quindi modificato con jQuery tramite rimozione di una classe:

$('.container').removeClass('active'); 

Questo riduce l'altezza da 200px per 15px.

Dopo di che, una regola di transizione viene applicata al contenitore mediante aggiunta di una classe:

$('.container').addClass('all-transition'); 

Quello che sta accadendo è che la riduzione dell'altezza si anima (su Firefox e Chrome, almeno). Nel mio mondo, questo non dovrebbe accadere se l'ordine delle istruzioni ha un significato.

Credo che questo comportamento può essere spiegato molto bene. Perché sta succedendo? Come posso impedirlo?

Questo è ciò che voglio raggiungere:

  1. modificare lo stile di default con jQuery (non animato da transizione CSS3!)
  2. Applica la regola di transizione con jQuery
  3. cambiamento di una proprietà con jQuery (animato per transizione CSS3)

(1) e (2) dovrebbero accadere il più rapidamente possibile, quindi non mi piace lavorare con ritardi arbitrari.

+0

Questo è davvero strano e forse un bug del browser. Ho aggiornato il violino per usare removeClass e inserire un'interruzione del debugger prima della prima funzione. http://jsfiddle.net/Danack/u9X4m/4/ Se passi alla prima funzione, quindi esegui il JS da lì, tutto funziona come ti aspetteresti. Senza la dichiarazione del debugger, c'è lo stesso strano effetto di animazione che stai vedendo. Non c'è codice in removeClass per usare qualsiasi animazione. Sto vedendo questo su Chrome btw. – Danack

+0

Chrome 25.0.1364.152 su mac - mostra l'animazione in modo errato. Safari 5.1.7 (6534.57.2) su mac - mostra l'animazione in modo errato. – Danack

+0

@abbood: sto vedendo un'animazione con Firefox 20 e Chrome 25 @ http://jsfiddle.net/zwatf/3/ –

risposta

4

Durante l'esecuzione di uno script, il browser di solito rimandano le modifiche del DOM alla fine per evitare il disegno non necessario. È possibile forzare un riflusso dalla lettura/scrittura di alcune proprietà:

var container = $('.container').removeClass('active'); 
var foo = container[0].offsetWidth; //offsetWidth makes the browser recalculate 
container.addClass('all-transition'); 

jsFiddle

oppure è possibile utilizzare setTimeout con una breve durata, che fa sostanzialmente la stessa cosa, lasciando il reflow del browser automaticamente, aggiungendo poi il classe.

+0

:-) Sì, grazie, la domanda correlata citata da @Bergi mi ha indirizzato verso questa tecnica. Farò alcuni test. Finora, questo "enforce-reflow-approach" mi sembra abbastanza affidabile. –

+0

Sì, ha funzionato per me sia in Aurora che in Canarie. IE10 non sembra avere il bug in primo luogo, ma aggiungere la linea non causa problemi. – Dennis

+0

Funziona, vedi http://jsfiddle.net/zwatf/8/ - Bergi mi ha indicato questo prima di te, quindi entrambi hai guadagnato il segno di spunta verde. Non so cosa fare;) –

1

penso, succede solo troppo veloce. Se si esegue questa operazione:

$('.container').toggleClass('active',function() { 
    $('.container').addClass('all-transition'); 
}); 

si comporterà come previsto, giusto?

ok, va bene, ho provato, ma non mi rendevo conto che non ha funzionato come previsto. Qui alternativa al lo compongono:

$('.container').removeClass('active').promise().done(function(){ 
    $('.container').addClass('all-transition'); 

    $('.container').css('height','300'); //to see the easing 
}); 
+1

No. ['.toggleClass'] (http://api.jquery.com/toggleclass/) non ha alcun parametro di callback – Bergi

+0

Bergi ha ragione. Non hai provato il tuo codice e non hai cercato la documentazione. Penso che non sia perché le cose stanno accadendo "troppo velocemente". Le cose accadono incontrollate. Venendo da altre lingue, mi sarei aspettato che quando 'removeClass' restituisse che l'azione è già stata già eseguita. Ovviamente, abbiamo a che fare con l'esecuzione asincrona. In questo caso, avere un parametro di callback sarebbe bello. –

+0

Non ho ancora provato l'approccio basato su 'promise', ma dalla documentazione corrispondente sembra che questo sia un approccio abbastanza ragionevole - ** se **" una volta che tutte le azioni di un certo tipo sono legate alla collezione, in coda o no, sono finiti "vale anche per il cambiamento dei CSS che dobbiamo aspettare. –

3

Perché che succede?

Immagino perché il DOM li vede applicati insieme; le azioni consecutive immediate vengono solitamente memorizzate nella cache anziché essere applicate una dopo l'altra.

Come posso impedirlo?

A (molto piccola) timeout dovrebbe farlo: http://jsfiddle.net/zwatf/4/

(dai commenti) innescando manualmente un riflusso aiuta anche: http://jsfiddle.net/zwatf/9/

non mi piace lavorare con i ritardi arbitrari.

Poi penso che l'unico altro modo possibile è quello di rimuovere il height dalle proprietà CSS animati, cioè è necessario dichiarare esplicitamente quali si voleva animare: http://jsfiddle.net/zwatf/5/

+0

Bergi, sai se jQuery è responsabile di questo comportamento di "memorizzazione nella cache" o se questo è il browser stesso? –

+0

No, questo è il browser stesso. Vedi http://stackoverflow.com/q/510213/1048572 – Bergi

+0

"Immagino perché il DOM li vede applicati insieme" Che dovrebbe essere pronunciato come "è un bug del browser". Il DOM è pensato per seguire le regole che vengono date, non solo per implementarle come ci si sente. – Danack