Skip to main content
Ben Nadel at CFCamp 2023 (Freising, Germany) with: Denis Burimov
Ben Nadel at CFCamp 2023 (Freising, Germany) with: Denis Burimov

Animation Timing-Functions Get Applied Per-Keyframe In CSS

By
Published in Comments (1)

A couple of weeks ago, I looked at creating a simple slide-show using dynamic keyframe animations in Angular 10.0.9. In the video for that demo, I mentioned that my approach was somewhat limited because the timing-function wasn't granular enough. As it turns out, my assumption of granularity was completely wrong. In fact, as I just learned from Una Kravets on the Animations episode of the CSS Podcast, the animation-timing-function property is applied on a per-keyframe basis. To help correct my poor mental model, I put together a small demo showcasing this per-keyframe granularity.

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

To demonstrate that the animation-timing-function within a CSS animation is applied on a per-keyframe basis, I am going to use cubic-bezier() function that moves a dot across the screen with a sort-of "bouncing" effect. This way, we can see that the dot "bounces" beyond the bounds of each keyframe configuration - not just beyonds the bounds the overall animation.

In the following CSS animation, the dot will rest at about 1/3 the horizontal distance; then again at about 2/3 the horizontal distance. At each resting point, we should see the cubic-bezier() animation-timing-function "bounce" the dot beyond the target left setting.

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8" />

	<title>
		Animation Timing-Functions Get Applied Per-Keyframe In CSS
	</title>
</head>
<body>

	<h1>
		Animation Timing-Functions Get Applied Per-Keyframe In CSS
	</h1>

	<style type="text/css">

		.track {
			border: 1px solid red ;
			border-radius: 100px ;
			height: 100px ;
			position: relative ;
		}

		.marker {
			background-color: red ;
			bottom: 0px ;
			position: absolute ;
			top: 0px ;
			width: 1px ;
		}

		.dot {
			background-color: #212121 ;
			border-radius: 80px ;
			height: 80px ;
			left: 10px ;
			position: absolute ;
			top: 10px ;
			width: 80px ;
			z-index: 2 ;
			/*
				In order to demonstrate that the timing-function executes per-keyframe,
				I'm going to use an exaggerated cubic-bezier configuration that "bounces"
				the dot past the final "left" value of each keyframe.
			*/
			animation-direction: alternate ;
			animation-duration: 10s ;
			animation-iteration-count: infinite ;
			animation-name: box-animation ;
			animation-timing-function: cubic-bezier( .55, -0.64, .42, 1.63 ) ;
		}

		@keyframes box-animation {
			from, 5% {
				left: 10px ;
			}
			25%, 40% {
				left: 30% ;
			}
			60%, 75% {
				left: 70% ;
			}
			95%, to {
				left: calc( 100% - 90px ) ;
			}
		}

	</style>

	<div class="track">
		<div class="dot">
			<br />
		</div>

		<!-- These markers help show the movement of the dot. -->
		<div class="marker" style="left: calc( 30% + 40px ) ;"></div>
		<div class="marker" style="left: calc( 70% + 40px ) ;"></div>
	</div>

</body>
</html>

And, when we run this CSS animation in the browser, we get the following output:

A dot moved across the screen using a bouncing animation per keyframe in CSS.

As you can see, the dot "bounces" beyond the target left alignment of each CSS keyframe. That's because the animation-timing-function is being applied on a per-keyframe basis - not to the entire animation life-span. This is a small but critical difference in how keyframe animations work. And now, hopefully, I'll remember this going forward.

Want to use code from this post? Check out the license.

Reader Comments

15,848 Comments

@All,

As a fast-follow to this post, I wanted to demonstrate that CSS Animation timing-functions can actually be changed per-keyframe:

www.bennadel.com/blog/3886-animation-timing-functions-can-be-changed-per-keyframe-in-css.htm

That's actually the piece of information that Una mentioned in the CSS Podcast - that the animation-timing-function can be overridden within a key-frame; which, in turn, led me to understand that the timing-function is also applied per-keyframe as well. Overall, it seems that CSS Animations are just a lot more powerful and dynamic than I had given them credit for.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel