My Tool Studio
CSS Generators·4 min read

CSS Keyframes Explained: Easing and Timing That Feel Right

A fade that takes 600ms with the right easing feels designed; the identical fade with linear timing feels like a rendering glitch. This is css keyframes explained for developers who'd rather tune values than memorize syntax: what a @keyframes block actually declares, how the animation shorthand wires it to an element, which easing curve fits which job, and the small set of properties you can animate without wrecking frame rates. Each example maps directly onto a preset in the CSS Animation Generator, so you can replay every variation live instead of imagining it.

CSS Animati…{"id": 0"ok": true}

Where keyframe animations appear in real interfaces

Mostly entrances, occasionally attention.

Watch any polished product and the keyframe inventory is short: content that fades and slides up a few pixels as it enters, skeleton placeholders pulsing while data loads, a notification badge that bounces once when the count changes, a modal that scales from 95% to full size.

None of these respond to a state change on the element itself; they play on their own schedule the moment the element appears, or they loop indefinitely. That autonomy is what separates keyframe animations from transitions, and it's why every one of them needs a named @keyframes rule to run.

CSS keyframes explained: snapshots, not scripts

A @keyframes rule is just named snapshots: @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }. You declare how things look at the start and the end; the browser computes every frame in between. From and to are aliases for 0% and 100%, and you can add stops like 60% for multi-stage motion.

The second half wires it up: animation: slideUp 600ms ease 0ms 1 normal both;. Reading the slots in order: the keyframes name, the duration, the easing curve, the delay, the iteration count, the direction, and the fill mode. That final both matters more than it looks: it holds the from state during any delay and freezes the to state after the last frame, which is what prevents the infamous snap back to the unstyled element.

Easing functions compared for keyframe motion

Easing is the personality of an animation, and the same keyframes read completely differently under different curves. linear moves at constant speed, correct for spinners and progress indicators and robotic for everything else. ease-out starts fast and decelerates, the default choice for entrances because elements appear to arrive and settle. ease-in accelerates away, suited to exits. ease-in-out does both, good for looping motion that reverses.

Custom curves earn their keep at the extremes. cubic-bezier(0.16, 1, 0.3, 1) leaps to most of its distance early and spends the rest of the duration settling, which makes panels feel weightless. cubic-bezier(0.34, 1.56, 0.64, 1) contains a value above 1, so the motion overshoots the target and springs back, a bounce without extra keyframes. Both ship as options in the easing dropdown of the CSS Animation Generator, and ten seconds of replaying each tells you more than any description.

Animation performance basics: the two-property rule

Browsers can animate opacity and transform on the compositor thread, skipping layout and paint entirely. Everything else costs more: animating width, height, top, or margin recalculates layout every frame, and animating box-shadow or background repaints large regions. On a mid-range phone, that's the difference between 60fps and a slideshow.

The practical rule: describe motion as transforms. Don't animate top: 20px to 0; animate translateY(20px) to translateY(0), the exact trade the slideUp example makes. Fade with opacity, grow with scale, move with translate, and treat any other animated property as a code smell that needs a justification.

Keyframes mistakes that make motion feel wrong

Most animation complaints trace to a handful of causes:

  • No fill mode, so the element snaps back to its pre-animation state on the final frame. End the shorthand with both and the bug disappears.
  • Durations past 800ms for interface motion. Users read long entrances as lag; 200 to 600ms covers nearly everything.
  • Infinite attention animations. A badge that bounces forever stops signaling and starts irritating; two or three iterations make the point.
  • Identical timing for enter and exit. Exits should be faster than entrances, since users have already decided to move on.
  • Ignoring prefers-reduced-motion. Wrap large movements in the media query and swap them for simple fades when the user asks for calm.

Keyframe animation habits that survive code review

Name every animation after its effect: slide-up, pulse-soft, badge-pop. Six months later, animation: anim2 800ms tells nobody anything. Naming by effect also stops accidental duplicates, since a second slide-up is obviously redundant in a way a second anim2 isn't.

For staggered lists, keep one shared keyframes rule and vary only animation-delay per item, 50 to 80ms of offset per row. The cascade effect looks elaborate but costs three lines, and every item stays in sync if you later retune the duration in one place.

Keyframes or a transition, and where transforms fit in

Choose by trigger. If motion should respond to a state change, hover, focus, a class toggle, a transition is simpler and cleans up after itself in both directions. If motion must run on its own, entrance effects, loops, anything with multiple stages, keyframes are the only option.

Either way, the values being animated are usually transforms, so the pose comes first. Work out the final translateY, scale, or rotation in the CSS Transform Generator, then decide whether that pose gets a transition or a full keyframes rule. Pose, then trigger, then timing: motion design in three decisions.

Try it now

Open CSS Animation Generator

The tool is one click away. No sign up, no upload, no payment.

Open CSS Animation Generator