글: Emmanuel Odioko✏️
오랫동안 수학 함수에 대한 제한된 지원으로 인해 시간 기반 CSS 애니메이션을 만드는 것이 훨씬 더 어려워졌습니다. 전통적인 애니메이션은 복잡한 계산을 기반으로 한 시간 기반 업데이트의 유연성이 부족한 키프레임과 지속 시간에 의존했습니다. mod(), round() 및 삼각 함수와 같은 CSS 함수의 도입으로 개발자는 이제 CSS에서 시간 기반 애니메이션을 마스터하는 방법을 탐색할 수 있습니다.
새로운 CSS 기능을 사용하여 CSS의 시간 기반 애니메이션에 대한 이 글을 최대한 활용하려면 CSS 애니메이션 및 전환에 대해 잘 이해하고 있어야 합니다. @keyframes를 사용하여 애니메이션을 생성하고 타이밍을 제어하는 방법을 알 수 있어야 합니다. 또한 DOM 요소를 조작하고 사용자 이벤트에 응답하는 기능에 더 중점을 두는 JavaScript에 대한 기본 이해가 있어야 합니다.
마지막으로 calc()와 같은 새로운 CSS 함수에 대한 이해와 mod(), sin() 및 cos()를 포함한 삼각 함수, round()와 같은 새로운 기능을 탐색할 준비가 되어 있으면 좋은 기초가 될 것입니다.
이 기사를 다 읽고 나면 JavaScript를 사용하여 HTML 캔버스에서 애니메이션이 전통적으로 어떻게 구현되었는지, 그리고 최신 CSS 기능과 어떻게 비교되는지 이해하게 될 것입니다. 기존 CSS 키프레임에 비해 mod(), round() 및 삼각 함수를 사용하는 것이 얼마나 쉬운지 이해하게 됩니다.
시간 기반 애니메이션은 새로운 것이 아닙니다. 10년 넘게 존재해 왔습니다. 일부는 사용하기 복잡하지만 일부는 그렇지 않습니다. 수학적 계산이 기본인 CSS 파일을 알고 계십니까? 시간 기반 애니메이션이 그 일부입니다.
이름에서 알 수 있듯이 이러한 애니메이션은 시간에 따라 위치, 크기, 색상, 불투명도 등 요소의 속성이 변경된다는 점에서 시간과 밀접한 관련이 있습니다. CSS 시간 기반 애니메이션은 웹 애플리케이션의 느낌을 향상시키고 더 나은 사용자 경험을 제공하는 부드러운 전환을 생성합니다.
시간 기반 CSS 애니메이션은 주로 정의된 시작 및 종료 타임라인과 보간 지점으로 구성됩니다. 여기서 보간이란 애니메이션이 진행됨에 따라 특정 기간 동안 애니메이션의 시작과 끝 사이의 중간 값을 계산하는 것을 의미합니다. 보간을 하는 이유는 초기 상태에서 최종 상태로의 원활한 전환을 제공하기 위한 것입니다.
시간 기반 애니메이션은 CSS 변수와 몇 가지 수학 함수의 조합으로 발생합니다. 이러한 통합을 통해 개발자는 시간이 지남에 따라 변경되는 애니메이션을 만들 수 있으며 키프레임 애니메이션에서는 꿈만 꿀 수 있는 보다 유연한 애니메이션을 만들 수 있습니다. 주요 개념과 작동 방식을 자세히 살펴보겠습니다.
이 섹션에서는 시간 기반 애니메이션을 만드는 일반적인 구조를 주요 구성 요소로 분석합니다.
초기 상태는 애니메이션이 시작되기 전 요소의 시작 속성을 정의합니다. 위치, 크기, 색상, 불투명도 등을 지정할 수 있습니다. 아래 예:
.box { opacity: 0; transform: translateY(-20px); }
위 코드에는 불투명도 및 변형 속성을 정의하는 상자 클래스가 있는 요소의 초기 상태가 있습니다.
애니메이션 트리거는 애니메이션을 시작하는 이벤트를 지정합니다. 일반적인 트리거에는 클릭이나 마우스 오버 등의 사용자 상호 작용, 페이지 로드 이벤트 또는 사용자 작업 완료와 같은 애플리케이션의 특정 조건이 포함됩니다.
애니메이션의 속성에는 애니메이션 지속 시간, 타이밍 기능, 지연, 반복 횟수, 방향 및 채우기 모드가 포함됩니다. 애니메이션에는 이러한 속성 중 일부 또는 전부가 있을 수 있습니다. 호버 선택기를 사용한 트리거 예시는 다음과 같습니다.
.box:hover { animation: fadeIn 1s ease-in-out forwards; }
이는 클래스 상자가 있는 요소에 마우스를 올려 놓을 때 트리거되고 1초간 지속되는 애니메이션 fadeIn의 추가를 보여줍니다. 애니메이션 동작과 타이밍도 지정됩니다. 애니메이션 및 전환 타이밍 기능에 대한 자세한 내용은 이 문서를 읽어보세요.
앞서 언급했듯이 이는 타임라인의 다양한 지점에 있는 애니메이션의 중간 상태입니다. 각 키프레임은 특정 순간의 요소 속성을 지정하여 초기 상태와 최종 상태 사이의 점진적인 전환을 허용합니다. 보간점 구현의 예는 CSS 키프레임 속성입니다.
@keyframes fadeIn { 0% { opacity: 0; transform: translateY(-20px); } 100% { opacity: 1; transform: translateY(0); } }
위의 예에서는 키프레임을 사용하여 애니메이션 진행률이 0과 100%인 fadeIn 애니메이션의 속성을 정의합니다.
Time-based animation has become increasingly essential in web applications as it helps with better user experience. The usage of these animations ranges from subtle micro-interactions to significant site transitions, giving web apps a more dynamic feel. Below are common use cases of these animations.
Micro-interactions are small, often subtle, and reusable animations that occur in response to user actions. These brief animations provide feedback. You may have come across animations such as pop-up warnings, loading spinners indicating ongoing processes, or a button indicating a click action. All of these are micro-interactions and consist of time-based animations. Image source: https://userpilot.com/blog/micro-interaction-examples/[/caption]
In the image above, we have a submit button which shows a loader and a tick when the user clicks on it. The essence of these micro interactions is to commit to the user the process of the submission and the success of the operation.
Site transitions are used to indicate state or page changes on a web application to create a fluid user experience using effects such as fading, sliding, or scaling elements. With time-based animations, these transitions are possible. Common transition effect applications are toggling navigation and side menus, parallax animations, opening and closing of modals, etc.
Image source: https://medium.com/@9cv9official/create-a-beautiful-hover-triggered-expandable-sidebar-with-simple-html-css-and-javascript-9f5f80a908d1[/caption] Image source: https://medium.com/@9cv9official/create-a-beautiful-hover-triggered-expandable-sidebar-with-simple-html-css-and-javascript-9f5f80a908d1
In the GIF above, there is a sidebar which uses a transition animation to expand the sidebar on a mouse hover event.
Let’s get into the new mathematical CSS functions mod(), round(), and the trigonometric functions sin(), cos() and tan() while discussing each in detail.
Like the JavaScript modulo operator %, this function returns the remainder after an arithmetic modulus operation has been carried out on two operands. In essence, the modulus is the leftover value after the dividend is divided by the other operand, the divisor, and no more division can occur. In JavaScript, using the modulo operator will take the following form:10%4.
This operation would leave behind a Modulus of 2 as 10 is only divisible by the divisor 4 twice, leaving behind a remainder of 2. Similarly, the CSS Mod function would perform the same function with the following syntax instead: mod(10, 4).
It is also important to note that the modulus takes the sign of the divisor. As such, the result of mod(10, -4) would be -2 instead.
The mod() function primarily accepts two sets of parameters mod(dividend, divisor) which are essentially two comma-separated values. These operands must be of the same dimension for them to be valid and can take a variety of values as parameters thereby improving the range of its application. Operands passed to mod() can be numbers, percentages, or dimensions.
Mod() can also take in the unit of its operands (e.g. px, rem, vh, deg) and can also handle mathematical calculations as dividend or divisor. Below are some examples showing the use of this CSS function:
/* using <numbers> without units */ scale: mod(18, 7); /* result is 4 */ /* <percentage> and <dimension> with units */ height: mod(100vh, 30vh); /* result is 10vh */ width: mod(500px, 200px); /* result is 100px */ transform: rotate(mod(90deg, 20deg)); /* result is 10deg */ /* negative <percentage> and <dimension> with units */ height: mod(18rem, -4rem); /* result is 2rem */ rotate: mod (180deg, -100deg); /* result is 80deg */ /* working with calculations */ width: mod(40px*2, 15px); /* result is 5px */ transform: scale(mod(2*3, 1.8)); /* result is 0.6 */ rotate: mod(10turn, 8turn/2); /* result is 2turn */
The code block above shows different applications of the mod() in CSS styles.
While the examples shown use known values, time-based functions are expected to be used with CSS variables which are dynamic and make it possible for the styles to change values depending on the variable passed to the function. The outcome of the operation is then dependent on the calculation using the specified variables, and can produce a wider range of outcomes compared to when hardcoded values are used.
Below you’ll find the general syntax for all possibilities of mod() as illustrated by MDN:
<mod()> = mod( <calc-sum> , <calc-sum> ) <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]* <calc-product> = <calc-value> [ [ '*' | '/' ] <calc-value> ]* <calc-value> = <number> | <dimension> | <percentage> | <calc-keyword> | ( <calc-sum> ) <calc-keyword> = e | pi | infinity | -infinity | NaN
In the syntax above, calc-sum represents the operands of the modulus operation. The syntax also shows the types of values calc-sum can contain and the possibility of negative and positive values. Furthermore, the syntax above also shows the possible calc-keywords e, pi, infinity, -infinity, and NaN.
The CSS round() function value is based on a specified rounding strategy. Note that strategy refers to the pattern of rounding the value such as rounding up or down, rounding to zero, rounding to the nearest occurrence of a number, etc..
The syntax for applying the CSS round() is given below:
round(<rounding-strategy>, valueToRound, roundingInterval)
Here's a breakdown of the CSS round() function into smaller bits and highlights of the functions of each keyword and the possible values they can take.
The rounding strategy is the type of technique that would be used to round a specified value. This is optional (defaults to nearest if unspecified), and can be one of the following:
This is the value we intend to round using the function, and it can be a
The rounding interval refers to the interval a value is rounded with a reference to. This entry can be a
Below is an example illustrating the use of the CSS round() function:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body{ display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; } /* using the round() function */ .ball { width: 100px; height: 100px; background-color: red; color: white; text-align: center; line-height: 100px; margin: 10px; } .ball-1{ border-radius: round(down, 70%, var(--rounding-interval)); /*rounded down to the interval of 50% */ } .ball-2{ border-radius: round(up, 70%, var(--rounding-interval2)); /* rounded up to interval of 100% */ } .ball-3{ border-radius: round(nearest, 15%, var(--rounding-interval3)); /* rounded to the nearest interval 25% */ } </style> </head> <body> <!-- rounded containers --> <div class="ball ball-1" style="--rounding-interval:50%;">rounded 50%</div> <div class="ball ball-2" style="--rounding-interval2:100%;"> rounded 100%</div> <div class="ball ball-3" style="--rounding-interval3:25%;"> rounded 25%</div> </body> </html>
In this example, we used round() and CSS variables to round values to a specified roundingInterval in the style of each element. Below is the outcome of this example: The formal syntax of the CSS round() function according to MDN docs is given by the following:
<round()> = round( <rounding-strategy>? , <calc-sum> , <calc-sum>? ) <rounding-strategy> = nearest | up | down | to-zero <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]* <calc-product> = <calc-value> [ [ '*' | '/' ] <calc-value> ]* <calc-value> = <number> | <dimension> | <percentage> | <calc-keyword> | ( <calc-sum> ) <calc-keyword> = e | pi | infinity | -infinity | NaN
In the syntax above, rounding-strategy is the intended rounding pattern and calc-sum represents the operands. The formula also shows the possible entries for rounding-strategy and calc-sum. Finally, it outlines the possible calc-keywords e, pi, infinity, -infinity, and NaN.
The CSS trigonometric functions perform the same operations as in mathematics, as such, the sin() function returns the sine of a number as a value between the range of -1 and 1, cos() returns the cosine of a value, and tan() returns the tangent of a specified value.
Arguments passed to these functions must be either a number or an angle, and they will be treated as radians. Units such as deg and turn represent angle and can be used with arguments here.
Example applications of these functions are shown below:
scale: sin(45deg); /* result is 0.7071067811865475 */ rotate: cos(30deg); /* result is 0.8660254037844387 */ height: calc(50px * tan(30deg)); /* result is 28.86751345948129px */
All trigonometric CSS functions bear similarity, taking in only a single parameter that is resolved to an angle.
Sin() takes in only one parameter which must be a number or angle, or a mathematical expression that resolves to either of them. The syntax of sin() is as follows: \
sin(angle)
The formal syntax of sin() is shown below: \
<sin()> = sin( <calc-sum> ) <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]* <calc-product> = <calc-value> [ [ '*' | '/' ] <calc-value> ]* <calc-value> = <number> | <dimension> | <percentage> | <calc-keyword> | ( <calc-sum> ) <calc-keyword> = e | pi | infinity | -infinity | NaN
The syntax above shows the possible values for calc-sum and calc-keyword.
The parameter of cos() is either a number, an angle, or contains a single calculation that must resolve to either type.
As such, the syntax for cos() is the following:
cos(angle)
The formal syntax of all possibilities of cos() is below:
<cos()> = cos( <calc-sum> ) <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]* <calc-product> = <calc-value> [ [ '*' | '/' ] <calc-value> ]* <calc-value> = <number> | <dimension> | <percentage> | <calc-keyword> | ( <calc-sum> ) <calc-keyword> = e | pi | infinity | -infinity | NaN
Where calc-sum is the parameter, calc-value is the allowed types of parameters, and calc-keywords are possible units that can be added to the mathematical expression.
The tan() function also takes a number, an angle, or a single calculation that must resolve to either type, similar to the other trigonometric functions. The syntax of tan() is given by the following:
tan(angle)
The formal syntax of this function is shown below:
<tan()> = tan( <calc-sum> ) <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]* <calc-product> = <calc-value> [ [ '*' | '/' ] <calc-value> ]* <calc-value> = <number> | <dimension> | <percentage> | <calc-keyword> | ( <calc-sum> ) <calc-keyword> = e | pi | infinity | -infinity | NaN
This syntax shows all possible values of calc-sum, the operand, and the calc-keyword.
In this section, we will create an animation using CSS functions, keyframes for an alternative, and JavaScript for a second alternative. In the end, we will compare the code and contrast the approaches to determine the benefits of usingCSS functions in creating CSS animations over other options.
Let's start by creating our music beat bar animation using CSS functions. This animation focuses on animating multiple bars, changing the property of the height and background colors using values generated with CSS functions:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Beats Bar Animation with CSS Functions</title> <style> :root { /* change the value of --t infinitely */ animation: animate-time 1000ms linear infinite; } @keyframes animate-time { from { --t: 0; } to { --t: 100000; } } body { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #222; margin: 0; } .container { height: 500px; width: 250px; position: relative; display: flex; gap: 10px; } .bar { position: absolute; bottom: 0; width: 20px; height: 20px; --frequency: 1; --time: calc(var(--t) / 1000 / var(--frequency)); --rounded-time: round(nearest, var(--time)); /* Adjust frequency of animation */ --amplitude: 30px; /* base height */ --base-height: 20px; /* Transition for smooth height change */ transition: height 0.5s ease-in-out, background 1s ease-in-out; /* Calculate dynamic hue using mod and round */ --hue: mod(round(nearest, calc(var(--time) * 10)), 360); --alpha: calc(0.5 + 0.5 * cos(calc(var(--time) * 1turn))); /* Apply dynamic linear gradient background */ background: linear-gradient(to top, hsla(var(--hue), 100%, 50%, var(--alpha)), hsla(calc(var(--hue) + 180), 100%, 50%, var(--alpha))); } .bar1 { /* Calculate height based on rounded time */ height: calc(var(--base-height) + var(--amplitude) * var(--rounded-time)/46 * var(--index-a)); margin-left: 10px; } .bar2 { /* Calculate height based on rounded time */ height: calc(var(--base-height) + var(--amplitude) * var(--rounded-time)/46 * var(--index-b)); margin-left: 30px; } .bar3 { /* Calculate height based on rounded time */ height: calc(var(--base-height) + var(--amplitude) * var(--rounded-time)/46 * var(--index-c)); margin-left: 50px; } .bar4 { /* Calculate height based on rounded time */ height: calc(var(--base-height) + var(--amplitude) * var(--rounded-time)/46 * var(--index-d)); margin-left: 70px; } .bar5 { /* Calculate height based on rounded time */ height: calc(var(--base-height) + var(--amplitude) * var(--rounded-time)/46 * var(--index-e)); margin-left: 90px; } .bar6 { /* Calculate height based on rounded time */ height: calc(var(--base-height) + var(--amplitude) * var(--rounded-time)/46 * var(--index-f)); margin-left: 110px; } .bar7 { /* Calculate height based on rounded time */ height: calc(var(--base-height) + var(--amplitude) * var(--rounded-time)/46 * var(--index-g)); margin-left: 130px; } .bar8 { /* Calculate height based on rounded time */ height: calc(var(--base-height) + var(--amplitude) * var(--rounded-time)/46 * var(--index-h)); margin-left: 150px; } .bar9 { /* Calculate height based on rounded time */ height: calc(var(--base-height) + var(--amplitude) * var(--rounded-time)/46 * var(--index-i)); margin-left: 170px; } </style> </head> <body> <div class="container"> <div class="bar bar1" style="--index-a: 1;"></div> <div class="bar bar2" style="--index-b: 2;"></div> <div class="bar bar3" style="--index-c: 4;"></div> <div class="bar bar4" style="--index-d: 6;"></div> <div class="bar bar5" style="--index-e: 8;"></div> <div class="bar bar6" style="--index-f: 6;"></div> <div class="bar bar7" style="--index-g: 4;"></div> <div class="bar bar8" style="--index-h: 5;"></div> <div class="bar bar9" style="--index-i: 2;"></div> </div> </body> </html>
Here’s a breakdown of the code block above:
The code above produces the following animation:
In this section, we will rebuild the sound bar animation, but we’ll use animations and CSS keyframes instead:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Beats Bar Animation with CSS Keyframes</title> <style> body { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #222; margin: 0; } .container { height: 500px; width: 250px; position: relative; display: flex; gap: 10px; } .bar { position: absolute; bottom: 0; width: 20px; height: 20px; --amplitude: 30px; --base-height: 20px; --frequency: 1; transition: height 0.5s ease-in-out; animation: bounce 1s infinite; } @keyframes bounce { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 0.5); } 50% { height: calc(var(--base-height) + var(--amplitude)); } } .bar1 { animation: bounce1 1s infinite, colorChange1 2s infinite; margin-left: 10px; } .bar2 { animation: bounce2 1s infinite, colorChange2 2s infinite; margin-left: 30px; } .bar3 { animation: bounce3 1s infinite, colorChange3 2s infinite; margin-left: 50px; } .bar4 { animation: bounce4 1s infinite, colorChange4 2s infinite; margin-left: 70px; } .bar5 { animation: bounce5 1s infinite, colorChange5 2s infinite; margin-left: 90px; } .bar6 { animation: bounce6 1s infinite, colorChange6 2s infinite; margin-left: 110px; } .bar7 { animation: bounce7 1s infinite, colorChange7 2s infinite; margin-left: 130px; } .bar8 { animation: bounce8 1s infinite, colorChange8 2s infinite; margin-left: 150px; } .bar9 { animation: bounce9 1s infinite, colorChange9 2s infinite; margin-left: 170px; } @keyframes colorChange1 { 0%, 100% { background: linear-gradient(to top, hsla(0, 100%, 50%, 1), hsla(180, 100%, 50%, 1)); } 50% { background: linear-gradient(to top, hsla(180, 100%, 50%, 1), hsla(360, 100%, 50%, 1)); } } @keyframes colorChange2 { 0%, 100% { background: linear-gradient(to top, hsla(30, 100%, 50%, 1), hsla(210, 100%, 50%, 1)); } 50% { background: linear-gradient(to top, hsla(210, 100%, 50%, 1), hsla(390, 100%, 50%, 1)); } } @keyframes colorChange3 { 0%, 100% { background: linear-gradient(to top, hsla(60, 100%, 50%, 1), hsla(240, 100%, 50%, 1)); } 50% { background: linear-gradient(to top, hsla(240, 100%, 50%, 1), hsla(420, 100%, 50%, 1)); } } @keyframes colorChange4 { 0%, 100% { background: linear-gradient(to top, hsla(90, 100%, 50%, 1), hsla(270, 100%, 50%, 1)); } 50% { background: linear-gradient(to top, hsla(270, 100%, 50%, 1), hsla(450, 100%, 50%, 1)); } } @keyframes colorChange5 { 0%, 100% { background: linear-gradient(to top, hsla(120, 100%, 50%, 1), hsla(300, 100%, 50%, 1)); } 50% { background: linear-gradient(to top, hsla(300, 100%, 50%, 1), hsla(480, 100%, 50%, 1)); } } @keyframes colorChange6 { 0%, 100% { background: linear-gradient(to top, hsla(150, 100%, 50%, 1), hsla(330, 100%, 50%, 1)); } 50% { background: linear-gradient(to top, hsla(330, 100%, 50%, 1), hsla(510, 100%, 50%, 1)); } } @keyframes colorChange7 { 0%, 100% { background: linear-gradient(to top, hsla(180, 100%, 50%, 1), hsla(360, 100%, 50%, 1)); } 50% { background: linear-gradient(to top, hsla(360, 100%, 50%, 1), hsla(540, 100%, 50%, 1)); } } @keyframes colorChange8 { 0%, 100% { background: linear-gradient(to top, hsla(210, 100%, 50%, 1), hsla(390, 100%, 50%, 1)); } 50% { background: linear-gradient(to top, hsla(390, 100%, 50%, 1), hsla(570, 100%, 50%, 1)); } } @keyframes colorChange9 { 0%, 100% { background: linear-gradient(to top, hsla(240, 100%, 50%, 1), hsla(420, 100%, 50%, 1)); } 50% { background: linear-gradient(to top, hsla(420, 100%, 50%, 1), hsla(600, 100%, 50%, 1)); } } @keyframes bounce1 { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 0.5); } 50% { height: calc(var(--base-height) + var(--amplitude) * 1.5); } } @keyframes bounce2 { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 1.5); } 50% { height: calc(var(--base-height) + var(--amplitude) * 2.5); } } @keyframes bounce3 { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 2.5); } 50% { height: calc(var(--base-height) + var(--amplitude) * 5); } } @keyframes bounce4 { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 4.5); } 50% { height: calc(var(--base-height) + var(--amplitude) * 8); } } @keyframes bounce5 { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 6.5); } 50% { height: calc(var(--base-height) + var(--amplitude) * 10); } } @keyframes bounce6 { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 4.5); } 50% { height: calc(var(--base-height) + var(--amplitude) * 8); } } @keyframes bounce7 { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 2.5); } 50% { height: calc(var(--base-height) + var(--amplitude) * 5); } } @keyframes bounce8 { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 1.4); } 50% { height: calc(var(--base-height) + var(--amplitude) * 2.8); } } @keyframes bounce9 { 0%, 100% { height: calc(var(--base-height) + var(--amplitude) * 0.5); } 50% { height: calc(var(--base-height) + var(--amplitude) * 1.6); } } </style> </head> <body> <div class="container"> <div class="bar bar1"></div> <div class="bar bar2"></div> <div class="bar bar3"></div> <div class="bar bar4"></div> <div class="bar bar5"></div> <div class="bar bar6"></div> <div class="bar bar7"></div> <div class="bar bar8"></div> <div class="bar bar9"></div> </div> </body> </html>
In the code above, we have styles for the body, container, and bar elements. We added an initial fallback animation state bounce and defined the animation properties with keyframes. Furthermore, we had to create separate keyframes animations for each bar’s height and background color change. The output of this animation is shown below:
Here, we will demonstrate how we can work with HTML, CSS, and JavaScript to recreate the animation in the previous section:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Beats Bar Animation with JavaScript</title> <style> body { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #222; margin: 0; } .container { display: flex; gap: 0; position: relative; } .bar { width: 20px; position: absolute; bottom: 0; transition: height 0.1s ease-in-out, background 0.1s ease-in-out; } .bar1 { left: 0; } .bar2 { left: 20px; } .bar3 { left: 40px; } .bar4 { left: 60px; } .bar5 { left: 80px; } .bar6 { left: 100px; } .bar7 { left: 120px; } .bar8 { left: 140px; } .bar9 { left: 160px; } </style> </head> <body> <div class="container"> <div class="bar bar1" data-index="1"></div> <div class="bar bar2" data-index="2"></div> <div class="bar bar3" data-index="3"></div> <div class="bar bar4" data-index="4"></div> <div class="bar bar5" data-index="5"></div> <div class="bar bar6" data-index="6"></div> <div class="bar bar7" data-index="7"></div> <div class="bar bar8" data-index="8"></div> <div class="bar bar9" data-index="9"></div> </div> <script> const bars = document.querySelectorAll('.bar'); const baseHeight = 100; // Base height of bars const amplitude = 150; // Amplitude of height changes const frequency = 2; // Frequency of the animation const animationSpeed = 0.1; // Speed of the animation function animateBars() { const currentTime = Date.now() / 1000; // Get the current time in seconds we will use this as a flux value bars.forEach((bar, index) => { // Calculate the height of the bar based on the current time const timeOffset = index * frequency; const height = baseHeight + amplitude * Math.abs(Math.sin(currentTime * frequency + timeOffset)); bar.style.height = `${height}px`; const hue = (currentTime * 50) % 360; // Dynamic hue based on time const alpha = 1; // alpha of 1 to avoid transparency at any point // Set the background color of the bar using a linear gradient bar.style.background = `linear-gradient(to top, hsla(${hue}, 100%, 50%, ${alpha}), hsla(${(hue + 180) % 360}, 100%, 50%, ${alpha}))`; }); requestAnimationFrame(animateBars); } function initializeBars() { // Set the initial height and color of the bars bars.forEach((bar, index) => { const initialHeight = baseHeight + amplitude * Math.abs(Math.sin(index * frequency)); bar.style.height = `${initialHeight}px`; const initialHue = (index * 50) % 360; // Initial hue based on index const initialAlpha = 1; // Set initial alpha to 1 to avoid transparency bar.style.background = `linear-gradient(to top, hsla(${initialHue}, 100%, 50%, ${initialAlpha}), hsla(${(initialHue + 180) % 360}, 100%, 50%, ${initialAlpha}))`; }); } // Initialize the bars with their initial heights and colors initializeBars(); // Start the animation animateBars(); </script> </body> </html>
In the code above, we styled the elements with CSS and created the HTML structure. We used JavaScript to select all elements with the class bar and also declared the variables. Next, we used a set of mathematical calculations to offset the bar height property and apply visual changes to the background gradient. The result is shown in the GIF below:
Let’s compare these different methods using certain technical aspects:
Technical aspect | CSS functions | Keyframes | JavaScript |
---|---|---|---|
Code length | Generally shorter, making use of variables and functions | Can be lengthy depending on the number of keyframes and the interpolation points defined | The length depends on factors such as the elements to be manipulated, the logic, and properties to be applied. |
Ease of implementation | Simple for dynamic, repetitive patterns | Simple for predefined animations | Complex logic handling and interaction |
Performance | High performance, offloaded to the GPU, and less CPU-intensive | High performance, offloaded to the GPU, less CPU intensive | Can be less performant, dependent on the JavaScript engine and the amount of JavaScript to be executed on the web |
Control | Dynamic and flexible | Static, predefined frames | Highly dynamic and interactive |
Maintenance | Easy to maintain, concise syntax | Easy to maintain but can get verbose | Can become complex and harder to maintain, and make changes to the logic |
Animation types | Best for simple, repetitive, mathematical animations | Great for detailed, multi-step animations | Best for interactive and responsive animations |
Reusability | High reusability with CSS variables since mathematical functions can create different values for the same variable | Moderate, requires duplication for different animations | High reusability with functions and logic |
Browser compatibility | `Mod()` and `Round()` are not compatible with Opera and Samsung browsers, the rest are fine | Keyframes have been around for a while, so it will be compatible for time-based animations | JavaScript is compatible with all browsers for time-based animations |
위에서 애니메이션에 사용할 때 CSS 기능이 다른 구현에 비해 단순성, 코드 재사용성, 제어 및 성능이 우수하다는 것을 알 수 있습니다.
이 기사에서는 mod(), round(), 삼각 함수에 이르는 시간 기반 애니메이션을 다루었습니다.
또한 이러한 기능을 키프레임 및 Javascript와 비교한 결과, 시간 기반 애니메이션이 복잡한 애니메이션에 비해 가볍고 성능에 영향을 미칠 가능성이 적기 때문에 주로 단순성, 향상된 재사용성 및 성능 최적화로 인해 성장한다는 것을 알 수 있었습니다. 애니메이션.
이는 결과적으로 사용자 경험을 향상하는 데 도움이 됩니다. 이러한 기능을 계속 탐색하고 코딩을 계속하세요!!
웹 프런트엔드가 점점 더 복잡해짐에 따라 리소스를 많이 사용하는 기능으로 인해 브라우저에서 점점 더 많은 것을 요구하게 됩니다. 프로덕션에 있는 모든 사용자의 클라이언트측 CPU 사용량, 메모리 사용량 등을 모니터링하고 추적하는 데 관심이 있다면 LogRocket을 사용해 보세요.
LogRocket은 웹 앱, 모바일 앱 또는 웹사이트에서 일어나는 모든 일을 기록하는 웹 및 모바일 앱용 DVR과 같습니다. 문제가 발생한 이유를 추측하는 대신 주요 프런트엔드 성능 지표를 집계 및 보고하고, 애플리케이션 상태와 함께 사용자 세션을 재생하고, 네트워크 요청을 기록하고, 모든 오류를 자동으로 표시할 수 있습니다.
웹 및 모바일 앱 디버깅 방법을 현대화하고 무료로 모니터링을 시작해 보세요.
위 내용은 새로운 CSS 기능으로 CSS 시간 기반 애니메이션 최적화의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!