preface
Hi, here is CSS and WebGL magic – Alphardex.
I’ve been playing three.js, and I’ve been exposed to a lot of mathematical functions and created a lot of special effects with them. So I thought: could I use these mathematical functions in CSS, but FOUND that CSS is not yet, it is said that a new specification will be included in the future, I guess it will take a long time to wait.
However, there are a few tricks you can use to create your own CSS math functions to achieve some interesting animations.
Let’s get started!
CSS mathematical functions
Note: the following functions can be implemented with native CSS, SCSS function is used here just for easy encapsulation, encapsulation is more convenient to call
The absolute value
Absolute value is positive or positive, negative becomes positive
You can create two numbers, one of which is the opposite of the other, and compare their maximum value to get the absolute value of that number
@function abs($v) {
@return max(#{$v}, calc(-1 * #{$v}));
}
Copy the code
The median
Subtract 1 and multiply by half
@function middle($v) {
@return calc(0.5* (# {$v} - 1));
}
Copy the code
The distance between two points on the number line
The distance between two points on the number line is the absolute value of the difference between the numbers represented by the two points
@function dist-1d($v1.$v2) {
$v-delta: calc(#{$v1# {} -$v2});
@return #{abs($v-delta)};
}
Copy the code
Trigonometric functions
Chokcoco wrote an article about how to implement trigonometry in CSS. Thank you
@function fact($number) {
$value: 1;
@if $number>0 {
@for $i from 1 through $number {
$value: $value * $i; }}@return $value;
}
@function pow($number.$exp) {
$value: 1;
@if $exp>0 {
@for $i from 1 through $exp {
$value: $value * $number; }}@else if $exp < 0 {
@for $i from 1 through -$exp {
$value: $value / $number; }}@return $value;
}
@function rad($angle) {
$unit: unit($angle);
$unitless: $angle / ($angle * 0 + 1);
@if $unit==deg {
$unitless: $unitless / 180 * pi();
}
@return $unitless;
}
@function pi() {
@return 3.14159265359;
}
@function sin($angle) {
$sin: 0;
$angle: rad($angle);
// Iterate a bunch of times.
@for $i from 0 through 20 {
$sin: $sin + pow(-1.$i) * pow($angle, (2 * $i + 1)) / fact(2 * $i + 1);
}
@return $sin;
}
@function cos($angle) {
$cos: 0;
$angle: rad($angle);
// Iterate a bunch of times.
@for $i from 0 through 20 {
$cos: $cos + pow(-1.$i) * pow($angle.2 * $i) / fact(2 * $i);
}
@return $cos;
}
@function tan($angle) {
@return sin($angle) / cos($angle);
}
Copy the code
example
The following animation effects demonstrate the above mathematical functions in action
One-dimensional staggered animation
The initial state
Create a row of elements, fill them with inner shadows, and prepare our math function
<div class="list">
<div class="list-item"></div>. (14 list-items omitted here)<div class="list-item"></div>
</div>
Copy the code
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background: # 222;
}
:root {
--blue-color1:#6ee1f5; } (Copy and paste all the mathematical formulas above here).list {
--n: 16;
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
&-item {
--p: 2vw;
--gap: 1vw;
--bg: var(--blue-color-1);
@for $i from 1 through 16{&:nth-child(#{$i}) {
--i: # {$i}; }}padding: var(--p);
margin: var(--gap);
box-shadow: inset 0 0 0var(--p) var(--bg); }}Copy the code
Application of animation
Two animations are used here: Grow is responsible for scaling elements out; Melt is responsible for “melting” elements (that is, eliminating the radius of shadow spread)
<div class="list grow-melt">
<div class="list-item"></div>. (14 list-items omitted here)<div class="list-item"></div>
</div>
Copy the code
.list{&.grow-melt {
.list-item {
--t: 2s;
animation-name: grow, melt;
animation-duration: var(--t);
animation-iteration-count: infinite; }}}@keyframes grow {
0% {
transform: scale(0); Were 50% and 100%} {transform: scale(1); }}@keyframes melt {
0%,
50% {
box-shadow: inset 0 0 0var(--p) var(--bg); 100%} {box-shadow: inset 0 0 0 0var(--bg); }}Copy the code
Staggered animation
- Calculates the median of the element’s subscripts
- Calculates the distance from each element ID to the median
- Calculate the scale based on the distance
- Calculate the delay according to the scale
<div class="list grow-melt middle-stagger">
<div class="list-item"></div>. (14 list-items omitted here)<div class="list-item"></div>
</div>
Copy the code
.list{&.middle-stagger {
.list-item {
--m: #{middle(var(--n))}; // The median is 7.5
--i-m-dist: #{dist-1d(var(--i), var(--m))}; // Calculate the distance between each ID and the median
--ratio: calc(var(--i-m-dist) / var(--m)); // Calculate the scale according to the distance
--delay: calc(var(--ratio) * var(--t)); // Calculate the delay according to the scale
--n-delay: calc((var(--ratio) - 2) * var(--t)); // Negative delay means animation starts early
animation-delay: var(--n-delay); }}}Copy the code
Address: Symmetric Line Animation
Two dimensional staggered animation
The initial state
How do I get from one dimension to two? Apply the grid system
<div class="grid">
<div class="grid-item"></div>. (62 grid-items omitted here)<div class="grid-item"></div>
</div>
Copy the code
.grid {
$row: 8;
$col: 8;
--row: #{$row};
--col: #{$col};
--gap: 0.25 vw;
display: grid;
gap: var(--gap);
grid-template-rows: repeat(var(--row), 1fr);
grid-template-columns: repeat(var(--col), 1fr);
&-item {
--p: 2vw;
--bg: var(--blue-color-1);
@for $y from 1 through $row {
@for $x from 1 through $col {
$k: $col * ($y - 1) + $x;
&:nth-child(#{$k}) {
--x: #{$x};
--y: #{$y}; }}}padding: var(--p);
box-shadow: inset 0 0 0var(--p) var(--bg); }}Copy the code
Application of animation
It’s exactly like the previous animation
<div class="grid grow-melt">
<div class="grid-item"></div>. (62 grid-items omitted here)<div class="grid-item"></div>
</div>
Copy the code
.grid{&.grow-melt {
.grid-item {
--t: 2s;
animation-name: grow, melt;
animation-duration: var(--t);
animation-iteration-count: infinite; }}}Copy the code
Staggered animation
- Calculates the median of the grid rows and columns
- Compute the distance from the grid xy coordinates to the median and sum
- Calculate the scale based on the distance
- Calculate the delay according to the scale
<div class="grid grow-melt middle-stagger">
<div class="grid-item"></div>. (62 grid-items omitted here)<div class="grid-item"></div>
</div>
Copy the code
.grid{&.middle-stagger {
.grid-item {
--m: #{middle(var(--col))}; // The median is 7.5
--x-m-dist: #{dist-1d(var(--x), var(--m))}; // Calculate the distance from the x coordinate to the median
--y-m-dist: #{dist-1d(var(--y), var(--m))}; // Calculate the distance from y to the median
--dist-sum: calc(var(--x-m-dist) + var(--y-m-dist)); // The sum of distances
--ratio: calc(var(--dist-sum) / var(--m)); // Calculate the scale based on distance and distance
--delay: calc(var(--ratio) * var(--t) * 0.5); // Calculate the delay according to the scale
--n-delay: calc(
(var(--ratio) - 2) * var(--t) * 0.5
); // Negative delay means animation starts early
animation-delay: var(--n-delay); }}}Copy the code
Address: Symmetric Grid Animation
Another kind of animation
Shuffle, an alternate animation, produces another peculiar effect
<div class="grid shuffle middle-stagger">
<div class="grid-item"></div>. (254 grid-items omitted here)<div class="grid-item"></div>
</div>
Copy the code
.grid {
$row: 16;
$col: 16;
--row: #{$row};
--col: #{$col};
--gap: 0.25 vw;
&-item {
--p: 1vw;
transform-origin: bottom;
transform: scaleY(0.1);
}
&.shuffle {
.grid-item {
--t: 2s;
animation: shuffle var(--t) infinite ease-in-out alternate; }}}@keyframes shuffle {
0% {
transform: scaleY(0.1); 50%} {transform: scaleY(1);
transform-origin: bottom;
}
50.01% {
transform-origin: top; 100%} {transform-origin: top;
transform: scaleY(0.1); }}Copy the code
Address: Shuffle Grid Animation
Cosine wave animation
The initial state
Create 7 different colored lists, each with 40 child elements, and each child element is a dot
Arrange the 7 lists in a line with staggered distances on the Z-axis, and set the basic delay
<div class="lists">
<div class="list">
<div class="list-item"></div>. (39 list-items omitted here)</div>. (6 lists omitted here)</div>
Copy the code
.lists {
$list-count: 7;
$colors: red, orange, yellow, green, cyan, blue, purple;
position: relative;
width: 34vw;
height: 2vw;
transform-style: preserve-3d;
perspective: 800px;
.list {
position: absolute;
top: 0;
left: 0;
display: flex;
transform: translateZ(var(--z));
@for $i from 1 through $list-count{&:nth-child(#{$i}) {
--bg: #{nth($colors.$i)};
--z: #{$i * -1vw};
--basic-delay-ratio: #{$i / $list-count};
}
}
&-item {
--w: 0.6 vw;
--gap: 0.15 vw;
width: var(--w);
height: var(--w);
margin: var(--gap);
background: var(--bg);
border-radius: 50%; }}}Copy the code
Cosine arrangement
Using the trigonometric formula above, arrange the dots as part of the cosine
.lists {
.list {
&-item {
$item-count: 40;
$offset: pi() * 0.5;
--wave-length: 21vw;
@for $i from 1 through $item-count{&:nth-child(#{$i}) {
--i: # {$i};
$ratio: ($i - 1)/($item-count - 1);
$angle-unit: pi() * $ratio;
$wave: cos($angle-unit + $offset);
--single-wave-length: calc(#{$wave} * var(--wave-length));
--n-single-wave-length: calc(var(--single-wave-length) * -1); }}transform: translateY(var(--n-single-wave-length)); }}}Copy the code
Fluctuations in the animation
Apply an up and down translation animation to each dot. The translation distance is the fluctuation distance of the cosine
.lists {
.list {
&-item {
--t: 2s;
animation: wave var(--t) infinite ease-in-out alternate; }}}@keyframes wave {
from {
transform: translateY(var(--n-single-wave-length));
}
to {
transform: translateY(var(--single-wave-length)); }}Copy the code
Staggered animation
Follow the above routine, calculate the delay from the middle, and then apply it to the animation
.lists {
.list {
&-item {
--n: #{$item-count + 1};
--m: #{middle(var(--n))};
--i-m-dist: #{dist-1d(var(--i), var(--m))};
--ratio: calc(var(--i-m-dist) / var(--m));
--square: calc(var(--ratio) * var(--ratio));
--delay: calc(
calc(var(--square) + var(--basic-delay-ratio) + 1) * var(--t)
);
--n-delay: calc(var(--delay) * -1);
animation-delay: var(--n-delay); }}}Copy the code
Address: Rainbow Sine
The last
CSS mathematical functions can achieve much more than this, I hope this article can inspire you to create special effects ~