120 companion flashcards · AI-assisted study content · Open the deck →
The material is well suited for beginner to intermediate web developers who want to move beyond static layouts and start adding smooth, interactive effects to their pages. If you're studying front-end design, preparing for a coding interview, or simply refreshing your CSS knowledge, these flashcards will help you lock in the syntax and terminology that make animations predictable and easy to debug.
To get the most out of your study sessions, try writing out each property and its value in a small HTML file as you go through the cards. Connecting the definitions to real code makes the timing functions and shorthand syntax much easier to remember. Spacing your reviews across several days rather than cramming will also help the distinctions between similar concepts, like jump-start and jump-end, stay clear in your mind.
CSS gives designers two complementary tools for motion on the web: transitions and animations. A transition is designed to animate smoothly between two states of a property when that property changes, interpolating intermediate values over time. An animation, by contrast, animates an element through multiple keyframes over time, supports loops and complex multi-step sequences, and runs automatically without requiring any state change to trigger it. In short, transitions react to changes, while animations drive a timeline on their own.
This distinction shapes when you reach for each tool. A transition needs an event — typically a pseudo-class like :hover or :focus, a class change, or a JavaScript style update — to begin, and it runs once between the old and new values. An animation can be defined declaratively with @keyframes and will play on its own schedule, optionally looping forever. The two can be combined: an animation may itself be paused or replayed by toggling a class, but the animation is not strictly dependent on that toggle to function.
It is also important not to confuse transition with transform. The transform property changes an element's geometry using functions like translate, rotate, and scale; transition is the mechanism that animates any animatable property when its value changes. Transforms are commonly the things being transitioned or animated, but transition itself does not move things — it animates changes.
A transition is enabled with the transition shorthand, which combines four longhand properties: transition-property, transition-duration, transition-timing-function, and transition-delay. The shorthand looks like transition: opacity 200ms ease-in-out, where you list a property, a duration, a timing function, and an optional delay. A common pitfall is forgetting that the first time value is duration and the second is delay — so transition: opacity 1s 200ms means a one-second transition that waits 200 milliseconds before starting.
transition-property names the CSS property (or "all") whose changes should be animated; its default is "all", which can cause unintended animations of properties you did not expect. Naming a specific property, like transition: transform 300ms, is safer and more performant. transition-duration sets how long the transition runs in seconds or milliseconds; the default is 0s, which effectively disables the transition and makes the change instant. transition-delay is the wait time before the transition begins, also defaulting to 0s.
A transition starts when the value of a watched property changes, which typically requires a pseudo-class such as :hover, a class change, or a JavaScript-driven style update. Only properties with a defined interpolation can be smoothly transitioned. Discrete properties like display cannot be animated and switch instantly; a common workaround is to combine visibility with opacity, or to apply a small transition-delay on display:none so the visible fade-out completes first. The visibility property itself is special: although it can be transitioned, it does not fade smoothly — it jumps at the midpoint, becoming hidden from 50% to 100% of the duration under a linear timing function.
Multiple properties can be animated in a single declaration by comma-separating them, each with its own duration and easing. JavaScript can listen for the transitionend event to chain further animations or clean up. Animating height: auto is not directly possible because auto has no fixed numeric value to interpolate from; modern CSS provides interpolate-size: allow-keywords to permit interpolation between keyword sizes like auto.
CSS animations are powered by the @keyframes rule, which defines named stages of a timeline and the styles an element should have at each stage. The syntax looks like @keyframes name { 0% { ... } 50% { ... } 100% { ... } }, where percentages mark keyframe positions. The keywords from and to are aliases for 0% and 100% respectively. Each keyframe selector can set any number of properties — transform, opacity, color, and so on — and the browser interpolates between them.
To apply an animation, the animation property is used together with @keyframes. The shorthand syntax is animation: name duration timing-function delay iteration-count direction fill-mode play-state, though only the first two are required. animation-name picks which @keyframes rule to use; without it, no animation runs. animation-duration sets the total length of one cycle, with a default of 0s that disables the animation. animation-iteration-count controls how many times the cycle repeats and can be a number or infinite, the default being 1. animation-direction sets the playback direction: normal, reverse, alternate (forward then backward), or alternate-reverse, defaulting to normal. A "ping-pong" effect is achieved with animation-direction: alternate.
animation-fill-mode determines what styles the element retains outside the animation runtime. Its values are none, forwards, backwards, and both. none (the default) means styles only apply while the animation is running; backwards applies the first keyframe's styles during any animation-delay period before the animation actually starts; forwards keeps the last keyframe's styles applied after the animation ends; both combines these behaviors. animation-play-state pauses or resumes the animation, accepting running or paused, and can be toggled on hover or via JavaScript.
animation-delay defers the start of the first iteration of an animation, which is different from transition-delay, which defers a single property change. A negative delay such as animation-delay: -1s starts the animation as if it had already been running, which is a useful trick to begin an animation mid-cycle. A common technique for staggering multiple animations is to give each element a different animation-delay, creating a cascading effect across a group. To loop seamlessly, set animation-iteration-count: infinite and make the 100% keyframe match the 0% keyframe so there is no visible jump. Note that animation-iteration-count controls how many times the cycle repeats and is independent of animation-duration, which controls the length of one cycle. JavaScript can react to the animationend event when an iteration finishes, and it can pause or restart animations by manipulating the animation property and forcing a reflow.
If a 0% or 100% keyframe is omitted, the browser uses the element's current style for that missing endpoint. Setting display: none on the element cancels any active animations or transitions; the animationend and transitionend events are not fired when this happens. To make a smooth slide-in from the left, for example, define @keyframes slideIn { from { transform: translateX(-100%); } to { transform: translateX(0); } } and apply it with a duration and easing.
Easing is the function that maps time progress to animation progress, controlling the perceived acceleration and deceleration of motion. CSS provides several built-in keywords. ease is the default and is equivalent to cubic-bezier(0.25, 0.1, 0.25, 1.0); it produces a gentle slow-fast-slow curve. linear is constant speed from start to end, equivalent to cubic-bezier(0, 0, 1, 1). ease-in starts slow and accelerates toward the end (cubic-bezier(0.42, 0, 1, 1)). ease-out starts fast and decelerates toward the end (cubic-bezier(0, 0, 0.58, 1)) and is good for elements coming to rest. ease-in-out accelerates in the middle and is slow at the start and end (cubic-bezier(0.42, 0, 0.58, 1)).
For custom curves, cubic-bezier() takes four numbers P1x, P1y, P2x, P2y. The x values must lie in the range 0–1 and represent time progress, while the y values represent value progress and may go outside 0–1 to create overshoot effects. Overshoot easing, where the animation goes past the target value before settling to create a spring-like feel, is achieved with a cubic-bezier whose y2 is greater than 1. The curve itself is a Bézier curve whose shape determines how the animation feels.
The steps() timing function divides an animation into a fixed number of discrete jumps instead of smoothly interpolating, producing a staircase-like progress. steps(n, jump-end) means the animation jumps at the END of each step: the element shows the start value until each step completes, then snaps to the next value. steps(n, jump-start) means the animation jumps at the START of each step, with the first value change shown immediately and n-1 more jumps following. The key contrast is that normal easing functions produce continuous, smooth interpolation, while steps() produces discrete frames.
For animations, animation-timing-function applies to the easing between each pair of adjacent keyframes, not across the whole animation, so different keyframe pairs can use different easings. Each keyframe selector in a @keyframes block can include its own animation-timing-function to control how it moves to the next. This allows, for example, a fast entry into a midpoint and a slow drift back out.
The transform property applies 2D or 3D transformations to an element without affecting surrounding layout. Common 2D transform functions include translate, which moves an element along an axis (transform: translate(50px, 0) shifts it 50 pixels right without affecting document flow); rotate, which spins it (transform: rotate(45deg) rotates it 45 degrees clockwise); and scale, which resizes it (transform: scale(1.5) enlarges the element to 1.5 times its size). Other functions include skew and matrix. The point around which transforms are applied is set by transform-origin, which defaults to 50% 50%, the element's center.
The order of transform functions matters because they apply right-to-left. transform: rotate(45deg) translateX(100px) is not the same as translateX(100px) rotate(45deg); the rotated-and-then-translated element ends up in a different position than the translated-and-then-rotated one. This often surprises newcomers building complex motions.
3D transforms use functions such as translate3d, rotateX, rotateY, rotateZ, and perspective to give an element depth. The perspective property sets the distance from the viewer to the z=0 plane, controlling the apparent depth of 3D transforms. There is a difference between perspective applied to a parent and the perspective() transform function applied to an element: perspective on the parent affects all child 3D transforms collectively, while perspective() as a transform function affects only that element. transform-style: preserve-3d makes child elements keep their 3D position relative to each other and the parent instead of being flattened to the 2D plane. backface-visibility controls whether the back side of a 3D-transformed element is visible; setting it to hidden hides the back and is useful for card-flip effects. transform: translateZ(0) is a legacy trick that hints the GPU to promote the element to its own layer, though modern code prefers the will-change property for this.
Browsers aim for 60 frames per second, meaning each frame should complete in roughly 16.7 milliseconds. To understand animation performance, it helps to know the rendering pipeline. After layout and paint, compositing is the final step where painted layers are combined into the screen image. Animations that only affect compositing — those using transform and opacity — can be handled by the GPU on the compositor thread without triggering layout or paint, so they animate smoothly even when the main thread is busy.
Animating properties that affect layout, such as width, height, top, left, or margin, forces the browser to recalculate layout on every frame, a phenomenon called "layout thrash" that severely hurts performance. Animating width versus transform: scaleX is a classic comparison: scaleX uses the GPU and does not trigger layout, while width triggers reflow every frame and is much slower. This is why animating transform and opacity is preferable to animating top/left, and why the typical frame rate of 60fps can drop sharply when layout-affecting properties are animated.
The will-change property hints to the browser that an element will be animated, often promoting it to its own compositor layer so the animation can run more smoothly. will-change: transform, opacity tells the browser to pre-allocate layers for those properties. However, will-change is not free: each layer consumes memory and GPU resources, and overusing it on many elements can hurt overall performance. It is best applied sparingly to elements that genuinely need the hint. Similarly, transition: all can cause performance issues because it animates every changing property, including unintended ones like filter or box-shadow that can be expensive.
Many common UI patterns are built from transitions and animations. The simplest hover effect uses a transition on a property that changes on :hover, for example a button that smoothly changes background-color on hover. A spinner — a small rotating element used to indicate loading — is typically made with animation: spin 1s linear infinite together with border-radius: 50% and @keyframes spin { to { transform: rotate(360deg); } }. A pulsing button uses animation: pulse 1.5s ease-in-out infinite with keyframes that scale between 1 and 1.05. A "pop" effect combines a quick scale-up with a fade-in, often transform: scale(0.8) → scale(1) together with opacity: 0 → 1.
A "ripple" effect, where a circular highlight expands and fades from a click point, is typically achieved with an absolutely positioned element, a scale animation, and an opacity transition. A staggered list is created by applying slightly different animation-delay values to each item so they animate sequentially rather than all at once, producing a cascade. SVG paths can be "drawn" by animating stroke-dasharray and stroke-dashoffset together, which moves the dash pattern along the path and creates a writing or erasing effect.
Accessibility is essential. The prefers-reduced-motion media query detects the user's OS-level setting to reduce motion, and designers use it to disable or simplify animations. Heavy animations can be wrapped in @media (prefers-reduced-motion: no-preference) { ... }, or alternatively the reduce branch can override durations and remove transforms. Continuous motion can trigger discomfort or vestibular issues for some users, so respecting this preference is an important accessibility practice. There is also a meaningful difference between opacity: 0 and visibility: hidden: opacity: 0 makes the element fully transparent but still clickable and in the layout, while visibility: hidden makes it invisible and unclickable yet still occupies layout space. To keep a transition target reachable for screen readers, pair opacity/transform with visibility: hidden/visible or with a delayed display: none so assistive technology treats the state correctly.
Several modern features extend what CSS animations can do. The @property rule declares a custom property with an explicit type, initial value, and inheritance, enabling the property itself to be animated; its typical syntax is @property --my-var { syntax: '
For more complex layout-driven motion, the FLIP technique (First, Last, Invert, Play) measures element positions with JavaScript before and after a layout change, then uses CSS transitions to animate the visual move smoothly. JavaScript can also control CSS animations directly: pausing is done by setting element.style.animationPlayState = 'paused', while restarting requires removing the animation property (or setting animation: none), forcing a reflow by reading something like element.offsetWidth, and then re-adding the original animation. CSS transitions are declarative, run on the compositor, and do not require JavaScript frames, whereas JS animations driven by requestAnimationFrame require code execution per frame. CSS transitions and animations are also generally preferred over SMIL, the SVG-native animation system using
Drill this topic
120 flashcards on CSS Animations & Transitions — free, no signup needed to start.
Study CSS Animations & Transitions flashcardsLearnWiki pages are generated with AI assistance from LearnCoachAssist's reviewed study catalog and may contain errors — verify anything critical against your course materials.