OK, starting with the CSS: to do a transition, you need to specify what you're transitioning from as well as what you're transitioning to, and the transition time should be on the "before" state (you have it on the "after" state).
So your CSS could look like this:
li {background-color: #FFF; transition: all 0.2s}
.effect { background-color: rgba(45, 171, 64, 0.1) }
(the 'no effect' li has a background color and the transition time; the 'with effect' has a different background color.)
Now on to the javascript:
if (!$('.list-item').hasClass('effect')){
$('.list-item').addClass('effect');
That "if" is harmless but unnecessary here. You can just call addClass
to add a class; if the element already has the class nothing will happen.
} else {
$('.list-item').removeClass('effect');
$('.list-item').addClass('effect');
I assume you're trying to trigger the transition again even on elements that already have the effect --- this won't work the way you have it, because the javascript will batch those DOM changes together, so as far as the DOM is concerned nothing changed at all.
Instead you need to remove the effect and then do a setTimeout
to bring it back.
Putting all that together results in:
$('.test').on("click",function() {
$('.list-item').removeClass('effect');
window.setTimeout(function() {
$('.list-item').addClass('effect');
}, 200); // <-- same duration as the transition
});
li {transition: all 0.2s; background-color:#FFF}
.effect { background-color: rgba(45, 171, 64, 0.1); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="list-item">data0</li>
<li class="list-item">data1</li>
</ul>
<div class="test">Click</div>
(Naturally in real life you'd probably want to apply this to a single list item instead of all of them as shown here; sounds from the comments like you have that part under control already).
Another method
A commenter points out that instead of setTimeout
you can trigger a DOM reflow by reading a property from the DOM between removing and re-adding the class, e.g.
$('.test').on("click", function() {
$('.list-item').removeClass('effect');
void this.clientWidth; // read any dom property, doesn't matter which
$('.list-item').addClass('effect');
});
This works well, but with one limitation: there can't be any transition duration set on the effect's exit. (In this case, if there's a transition duration set on li
the animation will not restart; if the duration is set only on li.effect
then it will work.) To demonstrate:
$('button').click(function() {
var li = $(this).prev('li');
li.removeClass('effect');
void this.clientWidth;
li.addClass('effect');
});
li {
background-color: #FFF; padding: 0.5em
}
li.effect {
background-color: #FFC;
transition: all 1s;
}
.b {
transition: all 1s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Here you can repeat the animation:</p>
<li>Item</li>
<button>This will work</button>
<p>...but here you can't (because the transition time on the 'li' prevents the effect from being visible):
<li class="b">Item</li>
<button>This will not work</button>