Is there a "pure CSS" way (not Less/Sass) of using the value of the nth-child
inside the CSS properties? Something like this:
span.anim:nth-child(N) { animation-delay: N * 0.5s; }
If there is, how can I do it? If there is not, how could I mimic it in a clean way? (I'm sure that I'm over-complicating things here)
I was creating a simple animation in which letters fade in while rotating. For that, I was using a combination of javascript (with jQuery) and CSS, but that created some problems (see below); so I tried to move to a CSS-only solution, and that ended in a large amount of rules.
This (simplified) CSS is common to both solutions:
span.anim {
font-size:30px;
opacity:0;
animation: anim 1s;
animation-fill-mode: forwards;
}
@keyframes anim {
from {
transform: rotate(0deg);
opacity:0;
}
to {
transform: rotate(360deg);
opacity:1;
}
}
Using JavaScript + CSS
My JavaScript code looks like this:
var aux = $("#animate").text();
$("#animate").text("");
for (var x = 0; x < aux.length; x++) {
setTimeout('$("#animate").append("<span class=\'anim\'>' + aux[x] + '</span>")', 500 * x);
}
This works great... unless the user moves to a different tab, then the animation messes up, and the result is unexpected. You can see it on this JSFiddle: http://jsfiddle.net/e7b9ygk4/ (run the script, move to a different tab, and go back after a few seconds).
Using only CSS
I can achieve the same effect by breaking the element in smaller elements (this is the part I feel I'm over-complicating), and then applying the animation to each element with a different delay:
span.anim:nth-child(1) { -webkit-animation-delay:0.5s; }
span.anim:nth-child(2) { -webkit-animation-delay:1.0s; }
span.anim:nth-child(3) { -webkit-animation-delay:1.5s; }
span.anim:nth-child(4) { -webkit-animation-delay:2.0s; }
span.anim:nth-child(5) { -webkit-animation-delay:2.5s; }
span.anim:nth-child(6) { -webkit-animation-delay:3.0s; }
span.anim:nth-child(7) { -webkit-animation-delay:3.5s; }
span.anim:nth-child(8) { -webkit-animation-delay:4.0s; }
span.anim:nth-child(9) { -webkit-animation-delay:4.5s; }
span.anim:nth-child(10) { -webkit-animation-delay:5.0s; }
span.anim:nth-child(11) { -webkit-animation-delay:5.5s; }
span.anim:nth-child(12) { -webkit-animation-delay:6.0s; }
span.anim:nth-child(13) { -webkit-animation-delay:6.5s; }
span.anim:nth-child(14) { -webkit-animation-delay:7.0s; }
span.anim:nth-child(15) { -webkit-animation-delay:7.5s; }
span.anim:nth-child(16) { -webkit-animation-delay:8.0s; }
This works great, even if the user moves to a different tab, but it results in a lot of unnecessary code (both HTML and CSS, although it could be simplified using JavaScript). You can see it working on this JSFiddle: http://jsfiddle.net/f5my3sm1/.
My gut tells me that this could be achieved using Sass/Less, but I want to know if there is a simple "pure CSS" way of doing this, something that could be achieved (hopefully) with a single rule like:
span.anim:nth-child(N) { animation-delay: N * 0.5s; }
CSS variables have almost universal support on all modern browsers and can achieve virtually the same desired effect as @GreatBlake's answer using attr
plus more. Instead of defining data in a user-defined attribute, you can define it as a custom property in the style
attribute and get the value of those custom properties using the var()
function:
span.anim {
display: inline-block;
font-size: 30px;
opacity: 0;
animation: fade-in-and-rotate 1s;
animation-fill-mode: forwards;
animation-delay: calc(var(--n) * 0.5s);
}
@keyframes fade-in-and-rotate {
from {
transform: rotate(0deg);
opacity: 0;
}
to {
transform: rotate(360deg);
opacity: 1;
}
}
<span class="anim" style="--n: 0">zero</span>
<span class="anim" style="--n: 1">one</span>
<span class="anim" style="--n: 2">two</span>
<span class="anim" style="--n: 3">three</span>
<span class="anim" style="--n: 4">four</span>
This code snippet also sets span.anim
's display
property to inline-block
for the question's provided rotate animation to work.
There is a very experimental CSS function for using attributes as properties for an element. Currently it only works on pseudo elements, so you'd have to consider coming up with some kind of clever re-working of your markup in this use case.
You could put the offset in a data-attribute on your markup (or with JS), and then use something like the following:
/* attr(name, units, fallback) */
span.anim {animation-delay: attr(offset, 1) * 0.5s;}
<span class="anim" offset="0"></span>
<span class="anim" offset="1"></span>
<span class="anim" offset="2"></span>
<span class="anim" offset="3"></span>
<span class="anim" offset="4"></span>
Please keep in mind that this is still a ways off from being widely accepted, and like I mentioned before, the above syntax wouldn't work currently because it would need to use pseudo elements like :after.
At the very least, it's something fun to think about.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With