Recently, I encountered an interesting problem by accident. I want to set the animation-duration value randomly. This is a non-random example:
This is an animation I wrote in CSS:
@keyframes flicker { 0% { opacity: 1; } 100% { opacity: 0; } } #red { animation: flicker 2s ease alternate infinite; }
It currently works well. But there is no randomization here, and the animation execution time is fixed at 2s.
The animation I want is a random number whose execution time is within 2s. The effect I want is like this:
.element { animation: flicker $randomNumber alternate infinite; }
The $randomNumber here is a random number generated by a specific function.
CSS preprocessor such as Sass provides such a function:
$randomNumber: random(5); .thing { animation-duration: $randomNumber + s; }
This may be what you want, but it is not what I want. The preprocessor generates random numbers. There is an obvious flaw:
Sass中,随机数生成过程就像是从一个故事中选择名字的过程,它仅仅在写完之后随机取出,然后它就不再变化了。 — jake albaugh (@jake_albaugh) 2016年12月29日
In other words, once the CSS preprocessor is executed, the randomization process is over, and the generated random number will be fixed to a value forever (that is, until The CSS preprocessor will be regenerated when it is run again. )
It does not generate random numbers when JavaScript is running like the random functions in JavaScript (such as Math.random()).
While deeply regretting it, I also realized that this was a perfect opportunity to use CSS variables (CSS’s own properties)! Although, using it to generate random numbers is not an easy task, they can still help us.
If you're not familiar with them, don't worry. In fact, CSS variables are a built-in feature of it, and are different from the variables you're already familiar with from CSS preprocessors like SASS and LESS. See the many benefits Chris lists here:
●You can use them without using preprocessing.
●They are cascaded. You can set the value of this variable or override the current variable reference in any selector.
●When their values change (such as media queries or other state changes), the browser will re-render.
●You can access them and manipulate them using JavaScript.
The last point is important to us. We generate random numbers in JavaScript and set the generated values to CSS variables.
Set a CSS custom property and give it a default value (this is useful in case JavaScript fails for some reason when writing the value):
/* 设置默认的动画执行时间 */ :root { --animation-time: 2s; }
Now we You can use this variable in CSS like this:
#red { animation: flicker var(--animation-time) ease alternate infinite; }
Without further ado, let’s get started immediately. Although this one looks like one of the previous SVG animations, this one is written using CSS variables. You can change the value of the variable to test how it works. And preview the effect in real time.
Now we use JavaScript to access and manipulate this variable:
var time = Math.random();
Here we can find the red circle created using SVG and use setProperty to change the value of --animation-time.
var red = document.querySelector('#red'); red.style.setProperty('--animation-time', time +'s');
Look here! A random number has been set to the SVG animation element:
Look at this example CSS random number #3 written by Robin Rendle (@robinrendle) on CodePen.
This is a big improvement over the previous one because its value is a random number generated when JavaScript is running, and it changes every time. This successfully achieves the effect we want, but we still have a little difficulty doing it: periodic animation-duration of a random number at runtime.
Luckily, we can now use JavaScript, we The value of a custom variable can be updated according to what we want. Here is an example where we update the value of animation-duration every second:
var red = document.querySelector('#red'); function setProperty(duration) { red.style.setProperty('--animation-time', duration +'s'); } function changeAnimationTime() { var animationDuration = Math.random(); setProperty(animationDuration); } setInterval(changeAnimationTime, 1000);
This is exactly what I want: Check out this example of CSS random numbers #4 by Robin Rendle (@robinrendle) on CodePen.
But you have to remember that the support for CSS variables (custom attributes) is still not very good, so be careful when using it. We can implement a progressive enhancement animation like this:
#red { animation: flicker .5s ease alternate infinite; animation: flicker var(--animation-time) ease alternate infinite;}
If CSS variables are not supported we can also see part of the animation, although it is not the perfect look in my mind.
Thankfully, CSS variables are not the only way we can generate random animation-duration values. We can use JavaScript to manipulate the DOM and set the value directly to the style:
var red = document.querySelector('#red'); red.style.animationDuration = Math.floor(Math.random() * 5 + 1) + "s";
We can even wait for the animation to complete before setting a new time, if we want such an effect:
var red = document.querySelector('#red'); function setRandomAnimationDuration() { red.style.animationDuration = Math.floor(Math.random() * 10 + 1) + "s"; } red.addEventListener("animationiteration", setRandomAnimationDuration);
This is just a list of possible ways to achieve this. You can also use EQCSS to achieve this effect:
@element '#animation' { .element { animation-duration: eval('rand')s; }}
var rand = Math.random();EQCSS.apply();
Do you want CSS itself to be able to generate correct random numbers? I have so far I haven’t seen any relevant information. Even if there is, it may take me a while before I can actually use it.