CSS animations are a little like coffee: the ingredients matter, but the timing decides whether the experience feels smooth, chaotic, elegant, or like your browser just tripped over a rug. That is where the CSS animation timing function comes in. It controls how an animation progresses during each cycle, deciding whether an element moves at a steady pace, starts slowly, speeds up, slows down, jumps in steps, or follows a custom curve.
In plain English, animation-timing-function is the speed personality of your CSS animation. Without it, a bouncing button might feel robotic. A sliding menu might look cheap. A loading indicator might feel suspiciously dramatic for something that is only fetching three lines of JSON. Used well, timing functions make web animations feel natural, polished, and intentional.
This guide explains how the CSS animation timing function works, when to use each value, and how to apply it with nine practical examples you can copy, tweak, and proudly pretend you wrote before lunch.
What Is the CSS Animation Timing Function?
The animation-timing-function property defines the speed curve of a CSS animation. It does not set how long the animation lasts; that job belongs to animation-duration. Instead, it controls how the animation travels through that duration.
For example, imagine an element moving from left to right over two seconds. With linear, it moves at the same speed the entire time. With ease-in, it starts slowly and then accelerates. With ease-out, it starts quickly and slows down near the end. The distance and duration are the same, but the feeling is completely different.
Basic Syntax
You can also include the timing function inside the animation shorthand:
In that shorthand, slide is the animation name, 2s is the duration, ease-in-out is the timing function, infinite repeats the animation forever, and alternate makes it reverse direction each cycle.
Common CSS Animation Timing Function Values
CSS gives you several built-in timing functions. These are the dependable presets: not flashy, not needy, and usually exactly what you want.
linear
The linear value keeps the animation moving at a constant speed from start to finish. It is useful for loaders, rotating icons, progress bars, and anything that should feel mechanical or consistent.
ease
The ease value is the default in many animation contexts. It starts slowly, speeds up, and then slows down near the end. It works well for general UI movement because it feels softer than linear.
ease-in
The ease-in value starts slowly and accelerates. Use it when an element is leaving the screen, shrinking away, or gaining momentum.
ease-out
The ease-out value starts quickly and slows down. This is great for elements entering the screen because it feels like they settle naturally into place.
ease-in-out
The ease-in-out value starts slowly, speeds up in the middle, and slows again at the end. It is excellent for smooth, balanced motion such as modal transitions, image reveals, and carousel slides.
steps()
The steps() function divides an animation into a set number of jumps instead of a smooth curve. It is perfect for sprite animations, typewriter effects, blinking cursors, and retro game-style movement.
cubic-bezier()
The cubic-bezier() function lets you create a custom easing curve using four numeric values. It is the designer’s playground: powerful, flexible, and capable of making a tiny button feel like it hired a movement coach.
linear()
The newer linear() easing function allows multiple progress stops, making it useful for more complex, hand-tuned motion curves. It can mimic bounce-like or spring-like movement without relying on JavaScript, though browser support and project requirements should always be checked before using it in production.
Why Animation Timing Matters
Good animation timing improves user experience. It can guide attention, explain relationships between elements, reduce visual harshness, and make an interface feel more responsive. Bad timing, on the other hand, can make a site feel clumsy, slow, or distracting. Nobody wants a dropdown menu that enters like it is auditioning for a soap opera.
The key is matching the timing function to the purpose of the motion. Functional UI animations should usually be quick and subtle. Decorative animations can be more expressive. Loading animations should feel steady. Exit animations should not linger like a guest who keeps saying, “Well, I should get going,” but remains in your doorway for 14 more minutes.
How to Use animation-timing-function in CSS
The property works with CSS keyframe animations. First, define the keyframes. Then apply the animation to an element and choose the timing function.
For performance, it is usually best to animate transform and opacity instead of layout-heavy properties such as top, left, width, or height. Smooth timing cannot rescue an animation that forces the browser to recalculate layout every frame. That is like putting racing tires on a shopping cart.
9 CSS Animation Timing Function Examples
Below are nine practical examples showing how different timing functions change the feel of an animation.
Example 1: Linear Spinner
Use linear when the motion should remain consistent. A spinner is the classic example because uneven speed can make it look broken or weirdly emotional.
Example 2: Smooth Card Entrance with ease-out
When an element enters the screen, ease-out often feels natural because the element begins with energy and gently settles into position.
Example 3: Exit Animation with ease-in
Use ease-in when something leaves the interface. It starts gently and accelerates away, which helps the element feel like it is actually departing instead of being yanked offstage by an invisible intern.
Example 4: Modal Pop with ease-in-out
The ease-in-out value is balanced and calm, making it ideal for modal windows, panels, and overlays.
Example 5: Custom Button Bounce with cubic-bezier()
A custom cubic Bézier curve can create a lively overshoot effect. This is useful for playful buttons, badges, and microinteractions.
The values in cubic-bezier(.34, 1.56, .64, 1) create a springy feeling because the curve overshoots before settling. Use this sparingly. A tiny bounce can feel delightful; every element bouncing like popcorn in a thunderstorm feels exhausting.
Example 6: Typewriter Effect with steps()
The steps() function is ideal when you want motion to happen in discrete jumps. A typewriter effect is a popular use case.
Example 7: Sprite Animation with steps()
Sprite animations use a single image containing multiple frames. Instead of moving smoothly, the background jumps from one frame to the next.
In this example, steps(6) matches six sprite frames. If the number of steps does not match the artwork, the character may look like it is moonwalking through a printer jam.
Example 8: Per-Keyframe Timing
You can place animation-timing-function inside keyframes. When used this way, it controls the pacing from that keyframe to the next one.
This technique is helpful when one part of an animation should feel different from another. In a bounce, the upward motion and downward motion should not always share the same curve.
Example 9: Multiple Animations with Different Timing Functions
An element can run multiple animations at once, and each animation can use its own timing function. This is useful when movement and opacity need different pacing.
The slide uses ease-out so the element settles smoothly, while the fade uses linear so opacity changes evenly. This kind of small detail can make a user interface feel much more refined.
Best Practices for CSS Animation Timing Functions
Match the Motion to the User’s Expectation
Users do not consciously analyze easing curves, but they feel them. A menu should open quickly and clearly. A success checkmark can be more expressive. A loading animation should be steady. Choose timing based on what the animation communicates.
Use Short Durations for Interface Feedback
Most UI animations should be quick, often somewhere between 150ms and 500ms. Longer animations can work for storytelling or decorative effects, but they can make everyday interactions feel slow. Your navigation menu is not a documentary; it does not need a dramatic three-act structure.
Prefer ease-out for Entrances
Elements entering the screen usually feel better with ease-out. The motion starts with momentum and ends gently, which helps the element feel responsive without slamming into place.
Prefer ease-in for Exits
Elements leaving the screen often work well with ease-in. The slow start gives the user a moment to perceive the change, while the acceleration helps the element disappear efficiently.
Use linear for Repeating Mechanical Motion
Spinners, rotating icons, and progress loops usually benefit from linear. If the animation repeats forever, uneven easing can create an awkward pause at the start or end of every cycle.
Test on Real Devices
A timing function that looks smooth on a powerful desktop can feel sluggish on a low-end phone. Test animations in real conditions, especially if your site uses many moving elements.
Respect Reduced Motion Preferences
Some users prefer less motion due to vestibular disorders, concentration issues, or simple personal preference. Use the prefers-reduced-motion media query to reduce or remove nonessential animations.
Common Mistakes to Avoid
Using ease for Everything
The default ease value is useful, but it is not magic seasoning. Different interactions need different pacing. A tooltip, a page transition, and a spinner should not all move the same way.
Making Animations Too Slow
Slow animations can feel luxurious in a product demo and deeply annoying in a real interface. When users are trying to complete a task, motion should support the action, not demand applause.
Animating Expensive Properties
Changing layout properties can cause performance problems. Whenever possible, animate transform and opacity. These properties are typically easier for browsers to optimize.
Overusing Bouncy Curves
Custom curves are fun, but not every element needs to bounce, wobble, or overshoot. Use expressive easing where it adds personality. Use calm easing where users need clarity.
Real-World Experience: What Working With CSS Animation Timing Teaches You
After working with CSS animation timing functions on real interfaces, one lesson becomes clear very quickly: the difference between “nice animation” and “why does this feel off?” is often tiny. A button that scales with linear timing can feel stiff. The same button with a carefully chosen cubic-bezier() curve can feel responsive and premium. Nothing else changes. Same element, same duration, same keyframes. The timing function does the emotional heavy lifting.
One practical experience is that ease-out becomes your reliable friend for entrance animations. When cards, menus, notifications, or modals appear, users expect them to arrive quickly and settle smoothly. If the animation starts too slowly, the interface feels delayed. If it ends too abruptly, it feels cheap. ease-out often solves that balance without requiring a custom curve. It is the “smart casual” outfit of CSS motion: appropriate almost everywhere.
Another lesson is that linear is useful, but only in the right places. Beginners often use it because it sounds simple and predictable. However, constant speed can make natural movement look unnatural. A panel sliding into view with linear may feel mechanical, while the same panel using ease-out feels more human. On the other hand, a rotating loading spinner should usually be linear because users expect continuous motion. This is why timing functions should be selected by context, not by habit.
Custom cubic-bezier() values are where animation starts to feel like craft. They are especially useful for brand personality. A finance dashboard may need calm, conservative motion. A children’s learning app can get away with more bounce. An e-commerce add-to-cart animation might use a subtle overshoot to make the action feel satisfying. The trick is restraint. In production work, the best custom easing curves are often the ones users barely notice because they simply feel right.
The steps() function also teaches an important lesson: not every animation should be smooth. Typewriter text, sprite characters, countdown digits, and blinking cursors all need controlled jumps. Using a smooth easing function for those effects can ruin the illusion. When you want frame-by-frame behavior, steps() is cleaner than trying to fake it with awkward keyframe percentages.
Performance is another real-world concern. A beautiful timing function cannot fix a heavy animation that changes layout on every frame. Animating left, top, or width may work in a small demo, but it can become choppy on complex pages. In actual projects, switching to transform often makes the animation smoother before you even adjust the easing. Timing and performance work together; one handles the feeling, the other keeps the browser from sweating through its digital shirt.
Finally, accessibility should be part of every animation decision. Motion can help many users understand an interface, but too much motion can bother others. The best experience is flexible. Use timing functions to create clarity and polish, but also support prefers-reduced-motion so people can browse comfortably. Great CSS animation is not about showing off. It is about helping the interface communicate without shouting, tap dancing, or launching confetti every time someone opens a menu.
Conclusion
The CSS animation timing function is one of the most important tools for creating polished web motion. It controls the pace and personality of an animation, turning basic keyframes into movement that feels smooth, natural, playful, or precise. Whether you use built-in values like linear, ease-in, and ease-out, or advanced options like steps() and cubic-bezier(), the goal is the same: make motion support the user experience.
Start with simple timing functions, test them in context, and adjust based on how the animation feels. A well-timed animation can guide attention, improve perceived quality, and make your website feel alive without becoming a circus parade with a CSS file.




