The Ultimate Guide to CSS Keyframes Animation
Adarsh M
Posted On: April 22, 2024
125246 Views
35 Min Read
The saying “first impression is the last impression” holds true, especially for online user experience. According to Forbes, nearly 94% of a website’s initial impression is influenced by its web design.
With animations in Cascading Style Sheets (CSS), users receive feedback while navigating the site, like when they click a button or scroll down with a downward arrow animation. CSS keyframes animation, a technique that interpolates between styles, plays a crucial role in providing these dynamic transitions.
Thanks to the CSS @keyframes property, achieving such effects only requires a few lines of code. This enhances the overall user experience, making the website more engaging and visually appealing.
In this blog, we will delve deeper into CSS keyframes animation, exploring how they work and their practical applications.
- Overview of CSS Animations
- What are CSS Keyframes Animation?
- Easing and Timing Functions of CSS Keyframes Animation
- Keyframes Animation Using CSS Transformations
- CSS Keyframes Animation Using Motion Path
- Keyframes Animation Using CSS Sprites
- CSS Variables for Dynamic Animations
- Maximizing Performance for CSS Animations and Keyframes
- Minimize Layout and Paint Operations
- Making Your CSS Keyframes Animation Accessible
- Debugging CSS Keyframes Animation
- Testing the Responsiveness of CSS Keyframes Animation
- CSS Keyframes Animation Best Practices
- Frequently Asked Questions (FAQs)
Overview of CSS Animations
Having some cool transitions and eye-catching animations shows that CSS animations have been used for hooking the users.
CSS animations are the means by which we can animate the transition from one state of CSS properties to another. It provides a simpler way for creating the illusion of motion and interactivity. CSS animations are typically more efficient in terms of performance because they can be offloaded to the browser’s GPU. This allows for smoother animations with minimal impact on CPU usage.
Let’s now see an example of a simple CSS animation where the element undergoes various translations, transformations, etc.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Creative CSS Animation</title> </head> <body> <div class="ball-container"> <div class="ball"></div> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
body { background-color: #333; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; } .ball-container { width: 100px; height: 100px; position: relative; animation: bounce 2s infinite; } .ball { width: 100px; height: 100px; background-color: #3498db; position: absolute; animation: spin 3s linear infinite, colorChange 5s infinite alternate, circleToTriangle 5s ease-in-out infinite alternate; } @keyframes circleToTriangle { 0%,100% { clip-path: circle(50% at 50% 50%); } 50% { clip-path: polygon(50% 0%, 100% 100%, 0% 100%); } 75%{ clip-path: polygon(20% 0%, 80% 0%, 100% 100%, 0% 100%); } } @keyframes bounce { 0%, 100% { transform: translateY(0); } 25% { transform: translateY(-200px); } 75%{ transform: translateY(200px); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes colorChange { 0% { background-color: #3498db; } 50% { background-color: #e74c3c; } 100% { background-color: #3498db; } } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
In the above example, you can observe a series of transformations, translations, and visual changes in the webpage. CSS animations open a door for creativity, allowing the use of several animation properties to create eye-catching user experiences.
Talking about browser compatibility, almost all modern browsers have good support for CSS animations.
Even though CSS animations are compatible with most modern browsers, achieving smooth animations across various screen sizes and devices can be a nuanced task.
To thoroughly test your CSS animations across different browsers, versions, devices, and platforms, you can leverage the Real Time Testing feature provided by LambdaTest.
Testing on AI-powered test orchestration and execution platforms like LambdaTest can give you a better insight about how end users see your web application. You can test on a remote test lab of 3000+ real browsers and operating systems.
Subscribe to the LambdaTest YouTube Channel. Get the latest updates on various automation testing tutorials covering mobile app testing, real device cloud, and more.
Now, let’s delve deeper into the CSS keyframes animation.
Test CSS keyframes animation across 3000+ real environments. Try LambdaTest Today!
What are CSS Keyframes Animation?
CSS animations consist of two fundamental components, animation styles and keyframes of the animation. These components work together to bring life and interactivity to web elements.
Let’s explore each of these components in-depth.
@keyframes Rule
The @keyframes rule allows you to specify a sequence of keyframes, each with its own set of CSS properties and values. These keyframes define the intermediate steps of an animation so that you can have better control over the animation at each timeline.
Here is a breakdown:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@keyframes animationName { 0% { /* Styles at the start of the animation */ } 25% { /* Styles at 25% progress */ } 50% { /* Styles at 50% progress */ } 75% { /* Styles at 75% progress */ } 100% { /* Styles at the end of the animation */ } } |
When you set an animation duration, you can segment the behavior of an element into different points along the timeline using percentage values. The percentage values (0%, 25%, 100%, etc., in this case) represent the progress of the animation, and you can add as many intermediate steps as needed.
Alternatively, in CSS keyframes animation, you have the option to use from and to keywords to specify the animation’s initial and final states concisely. The from keyword defines the animation’s starting point, while to keyword signifies its ending point, simplifying the control of CSS keyframes animation behavior.
Within each keyframe, you can specify CSS properties and values that define how an element should appear at that point in the animation. You can animate almost all the CSS properties, such as opacity, transform, color, and more, depending on your custom use case.
Between the CSS keyframes, the browser automatically interpolates the styles, ensuring a smooth transition between them. This interpolation creates the illusion of continuous motion.
You can also control keyframes animation with JavaScript, allowing you to trigger animations in response to user interactions or specific events like mouse movements.
JavaScript enables you to start, pause, or dynamically modify animations, opening the door to creating dynamic animations, such as mouse movement-based animations and more.
Here is how you can listen to a click event on an element to control the state of the animation.
JavaScript:
1 2 3 4 5 6 7 8 9 10 11 |
const Example__Element = document.querySelector('#Example__Element'); const Example__Element__2= document.querySelector('#Example__Element__2'); Example__Element.addEventListener("click", () => { element.style.animationPlayState = "running"; // Start the animation }); Example__Element__2.addEventListener("click", () => { element.style.animationPlayState = "paused"; // Pause the animation }) |
Let’s now discuss various CSS keyframes animation properties.
Animation Styles
Animation styles, also known as animation properties, define the overall behavior of the animation. These styles dictate various aspects of the animation, including its duration, timing function, delay, and more.
Here’s a breakdown of these CSS keyframes animation properties:
animation-name
The CSS property animation-name is used to indicate the specific animation to apply to an element. It can reference one or more @keyframes rules, which describe the animation’s behavior. You can specify multiple @keyframes rules by separating their names with commas.
Syntax:
1 2 3 |
.element__name { animation-name: myAnimation; } |
In the above syntax, the animation-name property is set to myAnimation, which refers to a previously defined CSS @keyframes rule. In cases where the provided name doesn’t match any existing @keyframes rule, no properties will undergo animation.
Here is an example of using the same CSS keyframes animation for multiple elements.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<html> <body> <div class="blog-container"> <!-- Blog Post --> <div class="blog-post"> <div class="skeleton"> <div class="skeleton-image"></div> <div class="skeleton-title"></div> <div class="skeleton-description"></div> <div class="skeleton-writer"> <div class="skeleton-writer-photo"></div> <div class="skeleton-writer-name"></div> </div> </div> </div> <!-- Blog Post --> <div class="blog-post"> <div class="skeleton"> <div class="skeleton-image"></div> <div class="skeleton-title"></div> <div class="skeleton-description"></div> <div class="skeleton-writer"> <div class="skeleton-writer-photo"></div> <div class="skeleton-writer-name"></div> </div> </div> </div> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
* { box-sizing: border-box; } body { margin: 0; font-family: 'Arial', sans-serif; background-color: #f0f0f0; } .blog-container { max-width: 800px; margin: 20px auto; padding: 20px; background-color: #f0f0f0; } .blog-post { background-color: #fff; border-radius: 8px; padding: 15px; margin-bottom: 20px; box-shadow: 0 3px 4px 0 rgba(0, 0, 0, .14), 0 3px 3px -2px rgba(0, 0, 0, .2), 0 1px 8px 0 rgba(0, 0, 0, .12); } .skeleton { display: flex; flex-direction: column; align-items: center; } .skeleton-image { width: 100%; height: 200px; border-radius: 8px; background: linear-gradient(-90deg, #ddd 25%, #eee 50%, #ddd 75%); background-size: 200% 100%; animation: skeletonLoading 1.5s infinite; margin-bottom: 15px; } .skeleton-title { width: 80%; height: 20px; background: linear-gradient(-90deg, #ddd 25%, #eee 50%, #ddd 75%); background-size: 200% 100%; animation: skeletonLoading 1.5s infinite; margin-bottom: 10px; } .skeleton-description { width: 90%; height: 12px; background: linear-gradient(-90deg, #ddd 25%, #eee 50%, #ddd 75%); background-size: 200% 100%; animation: skeletonLoading 1.5s infinite; margin-bottom: 10px; } .skeleton-writer { display: flex; align-items: center; } .skeleton-writer-photo { width: 75px; height: 75px; border-radius: 50%; background: linear-gradient(-90deg, #ddd 25%, #eee 50%, #ddd 75%); background-size: 200% 100%; animation: skeletonLoading 1.5s infinite; margin-right: 10px; } .skeleton-writer-name { width: 90px; height: 12px; background: linear-gradient(-90deg, #ddd 25%, #eee 50%, #ddd 75%); background-size: 200% 100%; animation: skeletonLoading 1.5s infinite; } @keyframes skeletonLoading { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
In the above example, you can see the skeleton loading animation that is being applied to various elements. Similarly, you can also have multiple animations for the same element by specifying the animation names, as well as the @keyframe rule for it.
You might have also noticed the use of another property called animation-duration here in the example. Let’s now look into that.
animation-duration
The animation-duration property defines the duration of time required for an animation to execute a full cycle, from its initial state to its final state and back to the beginning.
You can specify the animation-duration in either seconds (s) or milliseconds (ms). The value must be a non-negative number, and it’s essential to include the unit.
Syntax:
1 2 3 4 5 6 7 8 9 10 11 12 |
/* Using seconds (s) */ .element { animation-name: example; animation-duration: 2s; } /* Using milliseconds (ms) */ .element:hover { animation-name: example; animation-duration: 5000ms; } |
Here’s an example of three different loading CSS keyframes animation with varying durations.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>CSS duration example</title> </head> <body> <div class="wrapper"> <div class="loader1 loader"></div> <div class="loader2 loader"></div> <div class="loader3 loader"></div> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
body{ background: #111; } .loader{ margin:2cm; } .wrapper{ padding:16px; display:flex; align-items:center; justify-content:center; height:70vh } /* Loader 1 */ .loader1 { width: 50px; height: 50px; border: 8px solid #3498db; border-top: 8px solid transparent; border-radius: 50%; animation: spin 1s linear infinite; } /* Loader 2 */ .loader2 { width: 50px; height: 50px; border: 8px solid #e74c3c; border-top: 8px solid transparent; border-radius: 50%; animation: spin 2s linear infinite; } /* Loader 3 */ .loader3 { width: 50px; height: 50px; border: 8px solid #27ae60; border-top: 8px solid transparent; border-radius: 50%; animation: spin1 3s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
Each loader is a spinning animation with a different duration. The loader1 has a duration of 1 seconds, loader2 has a duration of 2 seconds, and so on. You can observe the varying speeds when viewing the webpage.
animation-timing-function
The animation-timing-function CSS property defines how an animation progresses through its keyframes over time. It specifies the pacing of the animation by determining the rate of change in the animated properties during each part of the animation cycle.
The animation-timing-function defines the speed curve, defining whether the animation begins slowly and accelerates, maintains a consistent speed, or follows a unique progression.
Syntax:
1 2 3 4 5 6 7 8 |
animation-timing-function: | linear | ease | ease-in | ease-out | ease-in-out | cubic-bezier(<number>, <number>, <number>, <number>) | steps(<integer> [, <step-position>]); |
The timing functions represent the type of easing function you want to apply to the animation. The timing functions in CSS are:
- linear: A linear easing function means that the animation progresses at a constant speed.
- ease: A standard easing function that starts slow, speeds up in the middle, and slows down at the end for smooth transitions.
- ease-in: An ease-in function means that it starts slow and gradually accelerates.
- ease-out: An ease-out function means that it starts fast and gradually decelerates.
- ease-in-out: An ease-in-out function that combines ease-in and ease-out behaviors.
- cubic-bezier(<number>, <number>, <number>, <number>): A custom cubic-bezier easing function is defined by four numeric values between 0 and 1. These values control the acceleration and deceleration of the animation.
- steps(<integer> [, <step-position>]): A step-based easing function with an integer value representing the number of discrete steps in the animation. You can also optionally specify the step position as start, end, or none to control when the step occurs.
Let’s now take an example and see how these animation timing functions work.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="description" content="CSS Animation Timing Functions"/> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>CSS Animation Timing Functions</title> </head> <body> <h1>CSS Animation Timing Functions</h1> <div class="container"> <div class="box ease">Ease</div> <div class="box ease-in">Ease In</div> <div class="box ease-out">Ease Out</div> <div class="box ease-in-out">Ease In Out</div> <div class="box custom">Custom (Cubic Bezier)</div> <div class="box steps">Steps</div> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
* { padding: 0; margin: 0; box-sizing: border-box; } body { font-family: Arial, Helvetica, sans-serif; text-align: center; background-color: #f2f2f2; } h1 { margin-top: 20px; color: #3497db; } .container { display: flex; flex-wrap: wrap; justify-content: center; margin-top: 20px; } .box { width: 100px; height: 100px; background: #1498db; margin: 20px; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 18px; animation-duration: 4s; animation-iteration-count: infinite; } .ease { animation-name: Movement; animation-timing-function: ease; } .ease-in { animation-name: Movement; animation-timing-function: ease-in; } .ease-out { animation-name: Movement; animation-timing-function: ease-out; } .ease-in-out { animation-name: Movement; animation-timing-function: ease-in-out; } .custom { animation-name: Movement; animation-timing-function: cubic-bezier(0.25, 0.5, 0.75, 1); } .steps { animation-name: Movement; animation-timing-function: steps(4, start); } @keyframes Movement { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(700px); } } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
You can see that all six boxes have the same animation named Movement but they all behave differently depending on the timing function.
Apart from the timing function, we can also set a delay to the animations, let’s now look into the animation-delay property.
animation-delay
The animation-delay property, as the name suggests, specifies the amount of time that an animation needs to wait before starting an animation. It accepts values in seconds(s) or milliseconds (ms).
The animation-delay property can also accept negative values. The negative value means that the animation will start before its scheduled start time. So, it will effectively appear as if the animation has already been in progress when it’s triggered.
Syntax:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.some-element { /* Delay the animation by 1 second */ animation-delay: 1s; } /* Start the animation immediately (no delay) */ .some-other-element { animation-delay: 0s; } /* Start the animation 500 milliseconds (0.5 seconds) earlier */ .another-element { animation-delay: -0.5s; } |
Here’s an example that showcases the use of the animation-delay property to create a delayed animations for a group of elements:
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>CSS duration example</title> </head> <body> <div class="fade-in"></div> <div class="fade-in"></div> <div class="fade-in"></div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
.fade-in { width: 100px; height: 100px; background-color: lightblue; margin: 10px; opacity: 0; /* Initially, elements are invisible */ animation-name: fadeIn, MoveRight; animation-duration: 1s,3s; animation-fill-mode: both; } .fade-in:nth-child(1) { animation-delay: 0.5s; /* Start first element after 0.5 seconds */ } .fade-in:nth-child(2) { animation-delay: 1s; /* Start second element after 1 second */ } .fade-in:nth-child(3) { animation-delay: 1.5s; /* Start third element after 1.5 seconds */ } @keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @keyframes MoveRight { 0%,100% { transform: translateX(0px); } 50% { transform: translateX(500px); } } button{ background:#111; color:white } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
We have three <div> elements with the class .fade-in, and each element has a delay set using the animation-delay property. The animation-delay creates a sequence where each element starts fading in after a specific delay, resulting in a staggered fade-in effect along with a translation in the +X direction
Thus, the animation-delay property can be used for creating animation sequences by staggering the start times of different animations.
animation-direction
The animation-direction property is used to determine how an animation should play. It controls the direction in which the animation progresses between its keyframes, such as forward or reverse. The animation-direction property is really useful for controlling the playback of CSS keyframes animation.
Syntax:
1 2 3 |
.element{ animation-direction: normal | reverse | alternate | alternate-reverse; } |
The animation-direction property accepts the following values:
- normal: It is the default value, and it plays the animation in the forward direction as specified in the keyframes. After that, it restarts from the initial position. The animation starts from the beginning and finishes at the last keyframe.
- reverse: The reverse animation plays backward from the end to the beginning. Then, it restarts from the end. Here, the animation begins with the last keyframe and then goes back to the first keyframe.
- alternate: The animation plays in a forward direction from the beginning to the end. Then, it reverses from the end to the beginning. It creates a ping-pong like effect. It alternates between forward and reverse cycles.
- alternate-reverse: The alternate-reverse is similar to the alternate property, but it starts by playing the animation backward from the end to the beginning.
Here’s an example of using the animation-direction property to create animations with different directions:
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>CSS duration example</title> </head> <body> <div class="box normal">Normal</div> <div class="box reverse">Reverse</div> <div class="box alternate">Alternate</div> <div class="box alternate-reverse">Alternate-Reverse</div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
.box { width: 100px; height: 100px; background-color: #3498db; margin: 20px; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 18px; animation-duration: 2s; animation-iteration-count: infinite; } /* Apply different animation directions */ .normal { animation-name: moveNormal; animation-direction: normal; } .reverse { animation-name: moveNormal; animation-direction: reverse; } .alternate { animation-name: moveNormal; animation-direction: alternate; } .alternate-reverse { animation-name: moveNormal; animation-direction: alternate-reverse; } /* Keyframes for the animations */ @keyframes moveNormal { 0% { transform: translateX(0) rotate(0); } 100% { transform: translateX(400px) rotate(180deg); } } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
We have four boxes with different animation directions: normal, reverse, alternate, and alternate–reverse. Each box uses a different animation direction by setting the animation-direction property accordingly.
animation-iteration-count
The animation-iteration-count property sets the number of times an animation should play. It accepts a numerical value to determine the iteration count. This property is useful for creating repetitive animations like loading animations etc.
Syntax:
1 2 3 |
.element { animation-iteration-count: infinite | <number> | initial | inherit; } |
- infinite: Setting animation-iteration-count to infinite causes the animation to repeat infinitely, creating a continuous loop.
- <number>: You can specify a particular number, such as 2, 3, or 5 to determine the exact count of animation repetitions.
- initial: This initial value will set the iteration count to its default value.
- inherit: The inherit value inherits the iteration count from the parent element.
Let’s take an example to visualize this property
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="styles.css"> <title>Animation Example</title> </head> <body> <h1> Animation iteration count </h1> <div class="box example1">Animate 3 times</div> <div class="box example2">Animates indefinitely </div> <div class="box example3">initial (default is 1)</div> <div class="box example4">inherit</div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
.box { width: 150px; height: 150px; background-color: skyblue; margin: auto; margin-top:15px; animation-name: moveBox; animation-duration: 2s; animation-timing-function: ease; color:white } h1{ text-align:center } @keyframes moveBox { 0% { transform: translateX(0); } 100% { transform: translateX(200px); } } .example1 { animation-iteration-count: 3; /* Repeats the animation 3 times */ } .example2 { animation-iteration-count: infinite; /* Repeats the animation indefinitely */ } .example3 { animation-iteration-count: initial; /* Resets to default value (1) */ } .example4 { animation-iteration-count: inherit; /* Inherits value from parent element */ } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
In the above example, you can see that we have four boxes moving horizontally. The animation-iteration-count property controls how many times the animation iterates based on the value assigned to the iteration count property.
animation-fill-mode
The animation-fill-mode property specifies how an element should be styled before and after an animation is played. It determines whether or not the element retains the styles applied during CSS keyframes animation when the animation is not actively running.
Syntax:
1 2 3 |
.example{ animation-fill-mode: none | forwards | backwards | both | initial | inherit; } |
The animation-fill-mode property can take the following values:
- none: The element does not retain any styles from the animation before or after it runs. It is the default value.
- forwards: The element retains the final keyframe styles after the animation completes. In other words, it sticks to the end state.
- backwards: The element retains the styles from the first keyframe when the animation is not running (before it starts).
- both: The element retains styles from both the first keyframe (before the animation starts) and the last keyframe (after the animation completes).
Here’s an example.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="styles.css"> <title>Animation Example</title> </head> <body> <div class="box none">None</div> <div class="box forwards">Forwards</div> <div class="box backwards">Backwards</div> <div class="box both">Both</div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
.box { width: 100px; height: 100px; background-color: #3498db; margin: 20px; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 18px; animation-name: move; animation-duration: 2s; animation-iteration-count: 1; } /* Keyframes for the animation (0% and 100% separately defined) */ @keyframes move { 0% { transform: translateX(0); background-color: #3498db; } 50% { transform: translateX(200px); background-color: #e74c3c; } 100% { transform: translateX(400px); background-color: #27ae60; } } /* Apply different animation fill modes */ .none { animation-fill-mode: none; } .forwards { animation-fill-mode: forwards; } .backwards { animation-fill-mode: backwards; } .both { animation-fill-mode: both; } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
In the above example, you can see how the animation-fill-mode property determines how an element should be styled both before and after the animation is executed.
Easing and Timing Functions of CSS Keyframes Animation
In the earlier section of the blog on CSS keyframes animation, we discussed a little bit about easing and timing functions. Let’s now take a deep dive into this.
Easing
Easing is like giving animations a natural touch. Think of it this way, when an object moves from point A to point B at a constant speed, it can seem a bit robotic, easing makes it smoother.
Without easing, it would move in a straight line, which often looks unnatural in user interfaces.
Easing functions provide a way to control the rate of change of an animation over its duration. These functions define the speed curve, determining how quickly or slowly an animation starts and ends.
Let’s take a look at some of the readily available easing functions in CSS:
linear
The linear timing function is the simplest and most straightforward of all timing functions. It creates a constant rate of change throughout the animation, meaning that the property being animated changes uniformly from the start value to the end value.
The animation occurs at a constant speed, and there are no sudden accelerations or decelerations. The speed curve will be a straight line graph.
Let’s take an example and visualize the linear timing function.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="styles.css"> <title>Moving Circle with Path</title> </head> <body> <div class="container"> <div class="path"></div> <div class="circle"></div> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
body { background-color: #f0f0f0; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; overflow: hidden; } .container { position: relative; width: 100%; height: 100px; } .path { width: 100%; height: 2px; background-color: #ccc; position: absolute; top: 50%; animation: movePath 5s linear infinite; } .circle { width: 40px; height: 40px; background-color: #3498db; border-radius: 50%; position: absolute; top: 50%; left: 0; animation: moveCircle 5s linear infinite; } @keyframes movePath { 0% { left: 0; transform: translateY(-50%); } 100% { left: 100%; transform: translateY(-50%); } } @keyframes moveCircle { 0% { left: 0; transform: translateY(-50%); } 100% { left: 100%; transform: translateY(-50%); } } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
In this example, we have a linear animation where the circle moves in the positive X direction without any acceleration or deceleration.
ease-in
The ease-in timing function is one of the predefined timing functions available in CSS animations and transitions. It is a common choice when you want to create an animation that starts slowly and gradually accelerates as it progresses.
The shape of the speed curve resembles a smooth, concave curve that starts gently and then becomes steeper as it progresses.
Let’s take the previous example and update the timing function from linear to ease-in and see the difference.
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
As you can see the path or the line goes in a linear fashion, whereas the circle starts slowly and gradually increases its speed of propagation.
ease-out
The ease-out timing function is another predefined timing function available in CSS keyframes animation and transitions. Unlike ease-in, which starts slowly and accelerates, ease-out does the opposite. It begins with a faster animation speed and then gradually decelerates as it reaches its end.
The speed time graph here resembles a smooth curve that starts quickly and then gradually levels off, giving the impression of a gradual slowdown.
Let’s add the ease-out property to the previous example now.
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
ease-in-out
The ease-in-out timing function is a commonly used predefined timing function in CSS keyframes animation and transitions.
As the name suggests, ease-in-out combines elements of both ease-in and ease-out, creating an animation that starts slowly, accelerates in the middle, and then decelerates as it approaches the end.
Let’s now update the previous example with an ease-in-out timing function.
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
In this example, you can see that the animations start slow, speed up in the middle, and end slowly.
Let’s combine all the predefined timing functions in a single example and see how it looks.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="styles.css"> <title>Animated Circles</title> </head> <body> <div class="container"> <div class="label">Linear</div> <div class="path"></div> <div class="circle linear"></div> </div> <div class="container"> <div class="label">Ease-In</div> <div class="path"></div> <div class="circle ease-in"></div> </div> <div class="container"> <div class="label">Ease-Out</div> <div class="path"></div> <div class="circle ease-out"></div> </div> <div class="container"> <div class="label">Ease-In-Out</div> <div class="path"></div> <div class="circle ease-in-out"></div> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
body { background-color: #f0f0f0; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; overflow: hidden; } .container { display: flex; flex-direction: column; align-items: center; margin: 20px; } .label { font-size: 16px; margin-bottom: 10px; } .path { width: 100%; height: 2px; background-color: #ccc; animation: movePath 5s ease-in-out infinite; } .circle { width: 40px; height: 40px; background-color: #3498db; border-radius: 50%; animation: moveCircle 5s linear infinite, easeInOut 5s linear infinite; } .ease-in { animation-timing-function: ease-in; } .ease-out { animation-timing-function: ease-out; } .ease-in-out { animation-timing-function: ease-in-out; } @keyframes movePath { 0% { transform: scaleX(0); } 100% { transform: scaleX(1); } } @keyframes moveCircle { 0% { transform: translateX(0); } 100% { transform: translateX(100%); } } @keyframes easeInOut { 0% { transform: translateX(0); } 50% { transform: translateX(50%); } 100% { transform: translateX(100%); } } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
From the output above, you can see how the animation behaves differently with respect to various timing functions. By selecting the right timing function, you can achieve effects that range from smooth and gradual transitions to bouncy, elastic movements.
Timing
The steps() function allows you to create CSS keyframes animation with defined steps rather than smoothly transitioning between values. This function can create frame-by-frame animations and show the changes in the property being animated.
Syntax:
1 2 3 |
.element { animation-timing-function: steps(value); } |
The value defines the number of intervals or steps the animation is divided into, and as an optional parameter, we can specify whether the steps start at the beginning (start) or end (end) of each interval.
Let’s now consider an example for demonstrating steps() function in animation by creating an animated clock movement.
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
In this example, you can observe that the animation durations are set to correspond to the full rotation for hours, minutes, and seconds. The steps() function is used to create a discrete step animation.
However, you might be wondering how to create custom timing functions for CSS keyframes animation. You are not limited to the predefined timing functions mentioned above, you can also create timing functions depending on your specific needs.
Let’s explore that now.
cubic-bezier() function
To achieve a natural and realistic finish in CSS keyframes animation, relying solely on a constant speed animation may not be ideal. For example, consider an animation where an object is dropped to the floor: it should first accelerate downward and then rebound after making contact with the floor. This nuanced effect can be accomplished through the use of cubic bezier curves.
The cubic-bezier() timing function is a cubic Bézier curve defined by four control points, which influence the acceleration and deceleration of animation over time.
The cubic-bezier() function specifies the timing of CSS keyframes animation, allowing you to create custom motion curves beyond standard timing functions like ease, linear, ease-in, and ease-out.
Syntax:
1 |
animation-timing-function: cubic-bezier(P0, P1, P2, P3) |
P0 and P3 represent the starting and ending points, respectively. They must be the coordinates (0, 0) and (1, 1). P1 and P2 are the control points, each with values between 0 and 1. P1 influences the curve’s initial acceleration. P2 influences the curve’s deceleration towards the end.
Let’s check out some simple animation timings created using the cubic-bezier() function.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="styles.css" /> <title>Cubic Bezier Animations</title> </head> <body> <h1>Cubic Bezier Animations</h1> <div class="wrap"> <span>ease | cubic-bezier(0.25, 0.1, 0.25, 1)</span> <div class="container"> <div class="box cb-0"></div> </div> <span>cubic-bezier(0.8, 0.1, 1, 0.04)</span> <div class="container"> <div class="box cb-1"></div> </div> <span>cubic-bezier(0.1, 0.9, 0.9, 0.1)</span> <div class="container"> <div class="box cb-2"></div> </div> <span>cubic-bezier(0.6, 1.5, 0.6, 1)</span> <div class="container"> <div class="box cb-3"></div> </div> <span>cubic-bezier(0.68, -0.55, 0.265, 1.55)</span> <div class="container"> <div class="box cb-4"></div> </div> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
body { background-color: #F5F5F5; color: #555; font-size: .9em; font-family: Consolas, monaco, monospace; } .wrap { margin: 30px auto 100px; max-width: 740px; } .container { padding: 0.1em; margin-bottom: 2.5em; border: 1px solid #333; background-color: white; } span { font-weight: medium; display: inline-block; margin-bottom: .8em; } .box { padding: 1em; width: 15px; height: 15px; background-color: purple; animation-duration: 3s; animation-name: moveCB; animation-iteration-count: infinite; animation-timing-function: cubic-bezier(.8, .1, 1, .04); } .cb-0{ animation-name: moveCB; animation-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1) } .cb-1 { animation-timing-function: cubic-bezier(0.8, 0.1, 0.1, 0.04) } .cb-2 { animation-timing-function: cubic-bezier(.1, .9, .9, .1); } .cb-3 { animation-timing-function: cubic-bezier(0.6, 1.5, 0.6, 1); } .cb-4 { animation-timing-function: cubic-bezier(0.68, -0.85, 0.265, 1.55); } .cb-5 { animation-timing-function: cubic-bezier(0.5, 3.0, 0.5, -2.0); } @keyframes moveCB { to { transform: translateX(635px); } } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
You can play around with the cubic-bezier() function to see the different curves that can be made.
The following are some of the most common timing functions you can use depending on your need for the CSS keyframes animation.
Now that we’ve covered CSS keyframes animation basics and timing functions, let’s dive into specific properties that we can adjust to create better CSS keyframes animation.
Keyframes Animation Using CSS Transformations
CSS transformations are a set of properties and functions that allow you to manipulate the visual rendering of HTML elements. They provide a way to change how HTML elements look and behavior on the webpage.
With transformations, you can make web elements bigger or smaller, move them around, rotate them, or even make them look like they’re slanted, all without changing the actual content of your web page.
Combining transformation with CSS keyframes animation can bring a new creative visual experience to the web. You can also use them to create 3D effects that bring depth to your web designs.
Let’s look at each of the transform functions available in CSS:
translate()
The translate() function allows one to move an element from one position to another along either the horizontal (x) or vertical (y) axis. It allows you to change the element’s location on the web page without altering its size, rotation, or other visual properties.
Syntax:
1 2 3 |
.element{ transform: translate(X, Y); } |
The X value specifies the distance to move the element along the horizontal (x) axis. It can be a positive or negative value, indicating rightward or leftward movement, respectively. Similarly, the Y value specifies the distance to move the element along the vertical (y) axis.
You can use either pixel values or percentage values for X and Y, depending on your design requirements. You can also use translateX() and translateY() functions separately if you only want to move the element along one axis.
In this example, we will try to translate the car in X direction. You can be creative and add more life-like animations to the website.
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
You can also use percentage (%) values inside the translate property, and it is a really useful way. When a percentage value is used to translate an object, that percentage refers to the element’s own size, not the available space within the parent container.
scale()
The scale() function in CSS defines a transformation that allows you to resize an element on the 2D plane. This can be useful in scenarios where we need CSS keyframes animation like creating zoom-in effects, transitions, or responsive designs.
Syntax:
1 2 3 |
.element{ transform: scale(X, Y); } |
The X value specifies the horizontal scaling factor. Values that are less than 1 make the element narrower, while a value greater than 1 makes it wider. Similarly, Y value specifies the vertical scaling factor. The values are unitless.
Let’s take an example to see it in action.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="styles.css"> <title>Image Zoom Effect</title> </head> <body> <div class="image-container i1"> <p>Scale X & Y</p> <img src="https://images.pexels.com/photos/15295967/pexels-photo-15295967/free-photo-of-food-light-water-leaf.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="Image 1"> </div> <div class="image-container i2"> <p>Scale X </p> <img src="https://images.pexels.com/photos/15295967/pexels-photo-15295967/free-photo-of-food-light-water-leaf.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="Image 1"> </div> <div class="image-container i3"> <p>Scale Y </p> <img src="https://images.pexels.com/photos/15295967/pexels-photo-15295967/free-photo-of-food-light-water-leaf.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="Image 1"> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
body { margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f0f0; } .image-container { width: 300px; height: 200px; overflow: hidden; position: relative; transition: transform 0.3s ease; margin:25px } img { width: 100%; height: 100%; object-fit: cover; } .i1:hover { transform: scale(1.2); /* Zoom in by 20% on hover */ } .i2:hover { transform: scaleX(1.2); /* Zoom in by 20% on hover on Y */ } .i3:hover { transform: scaleY(1.2); /* Zoom in by 20% on hover on Y */ } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
As you can see in the example, the image scales in response to the scale factor. This effect is often used in hover animations to provide users with a sense of interaction.
rotate()
The rotate() transformation function in CSS allows you to rotate elements, such as text or images, by a specified angle.
Syntax:
1 2 3 |
.element{ transform: rotate(angle); } |
The angle here specifies the angle of rotation in degrees. Positive values rotate the element clockwise, and negative values rotate counterclockwise.
Here is an example.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="styles.css"> <title>Card Flip Animation</title> </head> <body> <div class="card"> <div class="card-inner"> <div class="card-front"> <p>Test Your Web Or Mobile Apps On 3000+ Browsers</p> <img class="lambdatest" src="https://www.lambdatest.com/blog/wp-content/uploads/2023/05/Dashboard.png"/> </div> <div class="card-back"> <p class="sign">Sign Up</p> </div> </div> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
body { margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #333; } .card { width: 200px; height: 300px; } .card-inner { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; /* Preserve 3D transforms on child elements */ transition: transform 1s; /* Add a smooth transition for the flip effect */ } .card:hover .card-inner { transform: rotateY(180deg); /* Rotate the card 180 degrees on hover */ } .card-front, .card-back { height: 100%; width: 100%; position: absolute; backface-visibility: hidden; /* Hide the back of the card when it's flipped */ display: flex; flex-direction: column; justify-content: center; align-items: center; color: white; font-size: 24px; background: linear-gradient( 0deg, hsla(0, 0%, 100%, 0.3), hsla(0, 0%, 100%, 0.3) ), linear-gradient( 120.74deg, #ffb4b7 -1.19%, #deb5e7 29.65%, #84b5ff 62.61%, #c68cff 93.58% ); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* Add a box shadow for depth */ border-radius: 10px; overflow: hidden; } .lambdatest { width: 150px; } p { color: black; font-weight: 800; padding: 16px; } .card-back { transform: rotateY(180deg); /* Rotate the back of the card initially */ } .sign { border: 2px solid black; margin: 5px; padding: 12px; } |
See the Pen
Untitled by adarsh (@adarsh-gupta101)
on CodePen.
skew()
The skew() function distorts an element by skewing it along the x-axis, y-axis, or both. Skewing creates a parallelogram-like effect.
Syntax:
1 2 3 |
.element{ transform: skew(20deg, 10deg); } |
You can either pass a single value so that both x and y take the same value or pass two values to specify x and y separately. You can also use the skewX() and skewY() functions to determine the skewing along specific axes.
Let’s take an example to see an example skew animation.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <h1>Your Credit Card Wallet</h1> <div class="cards"> <div class="card"> <p>3872 4888 9812 0128</p> </div> <div class="card"> <p>9463 2378 1449 0548</p> </div> <div class="card"> <p>4554 4455 1738 0199</p> </div> <div class="card"> <p>5444 9583 4444 4463</p> </div> </div> </body> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
body { display: flex; height: 100vh; justify-content:center; align-items:center; background-color: #222; padding:15px; } h1{ color:white; font-family: monospace; font-size:24px; text-align; } .cards { display: flex; margin: auto; transform:rotate(270deg) } .card { position: relative; border-radius: 0.75rem; width: 8rem; height: 16rem; margin-left: -3rem; background-size: cover; cursor: pointer; box-shadow: inset 32px 32px 40px #ffffff30, inset 1px 1px 1px #ffffffaa, -24px 16px 32px #141418aa; transform: skewY(10deg); transition: all 0.25s ease-in-out; } .card:hover { transform: skewY(-15deg) translateY(-4rem); z-index:100 } .card p { position: absolute; bottom: 45%; right: 20%; transform: rotate(90deg); width: max-content; color: #ffffff90; font-family: monospace; text-shadow: 1px 1px 10px #fff; user-select: none; } .card:nth-child(1) { background-image: url("https://images.unsplash.com/photo-1596436950209-65ef85e9679c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1288&q=80"); } .card:nth-child(2) { background-image: url("https://images.unsplash.com/photo-1676893140106-1df79a4a7842?crop=entropy&cs=srgb&fm=jpg&ixid=M3wzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2ODc5NTExNzd8&ixlib=rb-4.0.3&q=85") } .card:nth-child(3) { background-image: url("https://images.unsplash.com/photo-1573788583117-2f62b3ddc08d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1287&q=80") } .card:nth-child(4) { background-image: url("https://plus.unsplash.com/premium_photo-1669863283269-7f1841a60648?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1288&q=80") } |
See the Pen
Credit cards by adarsh (@adarsh-gupta101)
on CodePen.
As you can see in the above example, skewing can produce a tilting effect on an element. This is useful for showing depth perception or achieving real-world-like visual effects.
Now that you have good knowledge of CSS keyframes animation using transformation effects let’s build an entire landing page with several animations.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Full Animated Website Example</title> <link rel="stylesheet" href="style.css" /> </head> <body data-colorMode="dark"> <div class="loader-wrapper"> <div class="loader"> <h3>#LambdaTest your Apps</h3> </div> </div> <nav> <div class="nav__logo"> <img src="https://www.lambdatest.com/resources/images/logos/logo.svg" alt="Lambdatest Logo" /> </div> <div class="nav__menu"> <div class="nav__burger" onclick="toggleMenu()"> <div class="bar line1"></div> <div class="bar line2"></div> <div class="bar line3"></div> </div> <ul class="nav__ul"> <li>Platform</li> <li>Enterprise</li> <li>Resources</li> <li>Developers</li> <li>Pricing</li> </ul> </div> <div class="nav__btns"> <button class="nav__signin">Upgrade</button> <button class="nav__signup">Book a Demo</button> </div> </nav> <div class="banner"> <div class="circle-container"> <img class="img_icon" alt="" src="https://cdn-icons-png.flaticon.com/128/2540/2540023.png?track=ais"/> <img class="img_icon" alt="" src="https://cdn-icons-png.flaticon.com/128/535/535160.png?track=ais"/> <img class="img_icon" alt="" src="https://cdn-icons-png.flaticon.com/128/5968/5968890.png?track=ais"/> <img class="img_icon" alt="" src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Opera_Mini_2015_icon.svg/512px-Opera_Mini_2015_icon.svg.png"/> <img class="img_icon" alt="" src="https://seeklogo.com/images/B/brave-logo-F5E1D99D9E-seeklogo.com.png"/> </div> <h2>The Complete Testing Solution for the Internet</h2> <p> Deliver unparalleled digital experience with our next-gen AI-powered testing cloud platform. Ensure exceptional user experience across all devices and browsers. </p> <div class="arrow" onclick=""> <!-- svg of an down arrow --> <svg id="scrl-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 38.9"><path class="scrl-body" d="M12.8 38.4h-1.6C5.2 38.4.4 33.6.4 27.6V11.2C.4 5.2 5.2.4 11.2.4h1.6c6 0 10.8 4.8 10.8 10.8v16.5c0 5.9-4.8 10.7-10.8 10.7z"/><path class="scrl-wheel" d="M12 13.9a4.2 4.2 0 01-4.2-4.2V4.2C7.8 1.9 9.7 0 12 0c2.3 0 4.2 1.9 4.2 4.2v5.4a4.1 4.1 0 01-4.2 4.3z"/></svg> </svg> </div> </div> <div class="video__banner"> <video loop="true" autoplay src="/HyperExecute.webm" /> </div> <div class="features"> <h3>Why Lambdatest?</h3> <div class="features__container"> <div class="card slide-left"> <h3>Online Cross Browser Testing Tool</h3> <p> Perform live interactive cross browser testing of your public or local websites on 3000+ real mobile and desktop browsers running on real operating systems. </p> </div> <div class="card slide-right"> <h3>Online Selenium Grid</h3> <p> A reliable, scalable, secure, and high performing test execution cloud that empowers development and testing teams to accelerate their release cycles. </p> </div> <div class="card slide-left"> <h3>HyperExecute</h3> <p> HyperExecute platform comes with feature-packed hosted runners for every major OS including Windows, MacOS, and Linux containers </p> </div> </div> </div> <footer> #LambdaTest your Apps </footer> </body> <script defer> function toggleMenu() { const navUl = document.querySelector(".nav__ul"); navUl.classList.toggle("show"); } const navLinks = document.querySelector(".nav__ul"); const links = document.querySelectorAll("li"); const hamburger = document.querySelector(".nav__burger"); hamburger.addEventListener("click", () => { //Animate Links navLinks.classList.toggle("toggle"); console.log(navLinks); links.forEach((link) => { link.classList.toggle("fade"); }); //Hamburger Animation hamburger.classList.toggle("toggle"); }); const cards = document.querySelectorAll(".card"); console.log(cards); cards.forEach((card) => { card.addEventListener("mousemove", (e) => { const rect = card.getBoundingClientRect(); const left = e.clientX - rect.left; const top = e.clientY - rect.top; console.log(left, top); card.style.setProperty("--left", `${left}px`); card.style.setProperty("--top", `${top}px`); }); }); document.addEventListener("DOMContentLoaded", function () { // Show the loader document.querySelector(".loader-wrapper").style.visibility = "visible"; document.querySelector(".loader-wrapper").style.opacity = "1"; // Set a timeout to hide the loader after 3 seconds setTimeout(function () { document.querySelector(".loader-wrapper").style.visibility = "hidden"; document.querySelector(".loader-wrapper").style.opacity = "0"; }, 3000); }); document.addEventListener('DOMContentLoaded', function() { const cards = document.querySelectorAll('.card'); function checkScroll() { cards.forEach((card, index) => { const cardPosition = card.getBoundingClientRect().top; const screenPosition = window.innerHeight / 1.3; // Adjust the position based on your preference if (cardPosition < screenPosition) { card.classList.add('show'); } }); } // Initial check when the page loads checkScroll(); // Check again when the user scrolls window.addEventListener('scroll', checkScroll); }); </script> </html> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 |
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap"); * { margin: 0; padding: 0; box-sizing: border-box; } body { /* dark mode */ background-color: #0e0505; color: #fff; font-family: inter, san-serif; padding: 16px; background: #000; } @keyframes pageLoad { 0% { background: #000; } 50% { background: #0ebac5; } 100% { background: #000; } } .loader-wrapper { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #000; z-index: 1000000; display: flex; align-items: center; justify-content: center; visibility: hidden; opacity: 0; transition: visibility 0s, opacity 0.5s linear; } .loader { width: 400px; height: 400px; display: flex; align-items: center; justify-content: center; position: relative; } .loader > h3 { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 2rem; font-weight: 800; margin-bottom: 1rem; text-align: center; padding: 16px; align-items: center; color: #0ebac5; } .loader::before { content: ""; width: 400px; height: 400px; position: absolute; top: 0; left: 0; border-radius: 50%; animation: ring 1s linear 4; } #scrl-icon { --clr: #ccc; display: block; width: 20px; height: auto; overflow: visible; margin: 10px auto; bottom: 50px; position: absolute; } .scrl-body { fill: none; stroke: var(--clr); stroke-linecap: round; stroke-miterlimit: 10; stroke-width: 3.5; animation: scroll-parallax 1.5s cubic-bezier(0.41, 0.07, 0.83, 0.67) infinite running; } @keyframes scroll-parallax { 25% { transform: translateY(0); } 75% { transform: translateY(-20%); } } .scrl-wheel { fill: var(--clr); transform-origin: bottom; animation: scroll-animation 1.5s linear infinite running; will-change: transform; } @keyframes scroll-animation { 0% { transform: translateY(-90%) scale(0.7, 0.1); } 10% { transform: translateY(-90%) scaleY(0.3); } 25% { transform: translateY(-20%) scaleY(1); } 75% { transform: translateY(40%) scaleY(1); } 100% { transform: translateY(20%) scale(0.8, 0.1); } } @keyframes ring { 0% { transform: rotate(0deg); box-shadow: 0px 5px 5px #ff2121; } 25% { transform: rotate(90deg); box-shadow: 0px 5px 5px #fffb21; } 50% { transform: rotate(180deg); box-shadow: 0px 5px 5px #21c0ff; } 75% { transform: rotate(270deg); box-shadow: 0px 5px 5px #bc21ff; } 100% { transform: rotate(360deg); box-shadow: 0px 5px 5px #ff2121; } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .nav__logo > img { filter: invert(1); } .nav__logo { flex: 0.1; } nav { display: flex; justify-content: space-between; align-items: center; } .nav__menu { display: flex; align-items: center; } .nav__burger { display: none; flex-direction: column; cursor: pointer; margin-right: 10px; } .bar { width: 25px; height: 3px; background-color: #fff; margin: 2px 0; animation: fadeIn 0.4s forwards; transition: all 0.3s ease-in-out; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .navbar li { opacity: 0; } li.fade { opacity: 1; transition: opacity 0.4s ease-in-out; } .toggle .line1 { transform: rotate(45deg) translate(5px, -6px); transition: all 0.7s ease; } .toggle .line2 { transition: all 0.7s ease; width: 0; } .toggle .line3 { transform: rotate(-45deg) translate(15px, -5px); transition: all 0.7s ease; } .nav__ul { display: flex; justify-content: space-between; align-items: center; flex: 0.7; list-style-type: none; z-index: 11; } .nav__ul li { margin-right: 20px; cursor: pointer; } .nav__btns { display: flex; } .nav__btns > button { margin: 0 10px; padding: 10px 20px; border-radius: 5px; border: none; cursor: pointer; font-size: 1rem; font-weight: 600; transition: all 0.3s ease-in; } @media (max-width: 768px) { .nav__burger { display: flex; } .nav__btns { display: none; } .nav__ul { display: flex; flex-direction: column; justify-content: center; position: absolute; top: 60px; left: 0; width: 100%; min-height: 90vh; background-color: #0ebac5; clip-path: circle(10px at 100% -30%); transition: all 0.8s ease-in; } .nav__ul.show { display: flex; clip-path: circle(100vh at 10% 10%); } .open { background-color: #0ebac5; clip-path: circle(100vh at 10% 10%); /* width: 100%; height: 100%; */ pointer-events: all; } .nav__ul li { margin: 0; padding-top: 45px; text-align: center; font-weight: font-bold; } } /* Banner text */ .circle-container { position: relative; animation: rotate 8s ease-in infinite; top: 30%; transform: scale(2.5) skew(100deg); filter: hue-rotate(10deg); } @keyframes rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .img_icon { width: 25px; height: 25px; position: absolute; top: 70%; left: 50%; transition: transform 4s ease-out; } .img_icon:nth-child(1) { transform: translate(-50%, -50%) rotate(0deg) translate(-250px) rotate(0deg); } .img_icon:nth-child(2) { transform: translate(-50%, -50%) rotate(72deg) translate(-250px) rotate(-72deg); } .img_icon:nth-child(3) { transform: translate(-50%, -50%) rotate(144deg) translate(-250px) rotate(-144deg); } .img_icon:nth-child(4) { transform: translate(-50%, -50%) rotate(216deg) translate(-250px) rotate(-216deg); } .img_icon:nth-child(5) { transform: translate(-50%, -50%) rotate(288deg) translate(-250px) rotate(-288deg); } .banner { height: 80vh; display: flex; flex-direction: column; justify-content: center; align-items: center; } @keyframes moveRound { 0% { transform: rotate(0deg) translate(0px, 0px); } 50% { transform: rotate(180deg) translate(25px, -< |