GODRICH

9 CSS Screen Transition Animation Effects

A CSS screen transition animation smooths every moment the screen changes — an image swap, a confirmed order, a form step — so the page glides from one state

Auto-plays · click a tile to jump to its section · all nine in one zip

The nine are ordered by the moments a visitor actually meets on a live page. The first scene opens like window blinds (01), a photo swings in on a string (02), the browsing mode glides between grid and list (03), the featured image swaps in place (04), a picked filter chip flies into its slot (05), an added product arcs into the cart (06), a ticket tears apart at confirmation (07), a form slides step by step in the direction you move (08), and finally a whole scene splits diagonally and gives way to the next one (09).

# Name What moves JS
01 Blinds slat reveal 6 slats scaleY cascade none
02 Polaroid swing-in card rotate damped swing none
03 Grid↔list view switch cards translate positions none
04 Main image slide swap scenes translateX crossing none
05 Filter chip slot-fill chip translate flight none
06 Fly-to-cart add dot double-translate arc none
07 Ticket-tear confirm two halves rotate apart none
08 Wizard step slide panels translateX ±100% none
09 Diagonal scene swap skew panels sweeping none

01Blinds slat reveal

When the page opens, six horizontal blind slats covering a bright headline panel fold away from the top one after another and uncover the text beneath. Instead of a hero headline flashing in all at once, it settles open slat by slat.

transform: scaleY:nth-child 계단transform-origin: top
.reveal__slat {
  transform-origin: top center;
  transform: scaleY(1);
  animation: slat-open $duration $easing both;
}
@keyframes slat-open {
  from { transform: scaleY(1); }
  to   { transform: scaleY(0); }
}
// each slat waits 90ms longer than the one above it
.reveal__slat:nth-child(2) { animation-delay: 90ms; }
.reveal__slat:nth-child(3) { animation-delay: 180ms; }

02Polaroid swing-in

A polaroid photo card hung from a single pin drops in tilted, sways left and right a few times, and comes to rest perfectly straight. Dropped onto a gallery intro or a travel-log thumbnail, it gives a static photo page a physical, handmade warmth.

rotate 오버슈트transform-origincubic-bezier
.swing {
  transform-origin: top center;   // the pin is the rotation axis
  animation: swing-in $duration $easing both;
}
@keyframes swing-in {
  0%   { transform: translateY(-70px) rotate(18deg); opacity: 0; }
  38%  { transform: rotate(-11deg); }
  56%  { transform: rotate(7deg); }
  72%  { transform: rotate(-4deg); }
  100% { transform: rotate(0deg); }
}

03Grid↔list view switch

The same three product cards glide between a two-column grid and a single-column list without ever leaving the frame. The toggle knob answers first and the cards follow, so the screen feels alive the instant you touch it.

translate 좌표 전환라디오 :checkedtransition
.vs__card { transition: transform $duration $easing; }
// percentages are relative to the card's own size — grid: one column to the right
.vs__card--2 { transform: translate(calc(100% + 8px), 0); }
.vs__card--3 { transform: translate(0, calc(100% + 10px)); }
// list: the same cards stack one row at a time
#vs-list:checked ~ .vs__board .vs__card--2 { transform: translate(0, calc(100% + 10px)); }
#vs-list:checked ~ .vs__board .vs__card--3 { transform: translate(0, calc(200% + 20px)); }

04Main image slide swap

Picking a thumbnail slides the current image out to the left while the new one enters from the right into the same frame. On a product page this turns an abrupt image swap into a small, flowing exchange that makes browsing feel rewarding.

translateX 교차opacity활성 썸네일 링
.gal__scene {
  position: absolute; inset: 0;
  transform: translateX(110%);              // waiting off-stage right
  transition: transform $duration $easing, opacity $duration $easing;
}
#gal-2:checked ~ .gal__frame .gal__scene--2 { transform: translateX(0); }
#gal-2:checked ~ .gal__frame .gal__scene--1 { transform: translateX(-110%); }  // exits left

05Filter chip slot-fill

Picking a color chip sends that chip flying from its row up into an empty outlined slot above, landing at exactly the same size. The choice registers as a physical object moving, not as text changing, which reads instantly on shopping screens.

translate 비행체크박스 :checked칩 잔물결
.pick__chip { transition: transform $duration $easing; }
// each chip has a different distance to the slot — chip 2 travels 96px left, 76px up
#pick-2:checked ~ .pick__row .pick__chip--2 {
  transform: translate(-96px, -76px);
  z-index: 2;                       // the flying chip floats above the row
}
#pick-2:checked ~ .pick__slot { border-color: rgba(255,255,255,.8); }

06Fly-to-cart add

Pressing Add sends one product-colored dot flying on an arc from the product card to the cart icon in the corner, fading away as it lands while the count badge bounces. Because the departure and arrival points share one screen, the visitor can follow their own action all the way to its destination.

이중 translate 포물선scale 축소배지 바운스
.cart__fly   { transition: transform $duration $easing; }   // outer element: x at constant speed
.cart__fly-y { transition: transform $duration $easing; }   // inner element: y on an eased curve
// landing coordinates come from measured getBoundingClientRect values
#cart-add:checked ~ .cart__fly { transform: translateX(273px); opacity: 0; }
#cart-add:checked ~ .cart__fly .cart__fly-y { transform: translateY(-71px); }
#cart-add:checked ~ .cart__bag .cart__badge { transform: scale(1.35); }

07Ticket-tear confirm

At the moment of confirmation the dashed line down the middle of the ticket lights up, and the left and right halves tilt away in opposite directions and exit the frame as two torn stubs. For irreversible moments like placing an order or checking in, this seals the action far more firmly than a text change.

rotate 분리opacity 퇴장점선 마디
.tear__half { transition: transform $duration $easing, opacity $duration $easing; }
#tear-ok:checked ~ .tear__ticket .tear__half--l {
  transform: translate(-52px, 26px) rotate(-9deg);   // left half: down-left
  opacity: 0;
}
#tear-ok:checked ~ .tear__ticket .tear__half--r {
  transform: translate(44px, 30px) rotate(8deg);     // right half: down-right
  opacity: 0;
}

08Wizard step slide

Moving to the next step slides the current panel out left and brings the new one in from the right, and going back reverses the direction exactly. You never have to read an arrow to know where you are in the flow, so multi-step forms stop feeling like a maze.

translateX ±100%진행 점방향별 전환
.wiz__panel { transition: transform $duration $easing, opacity $duration $easing; }
.wiz__panel--2 { transform: translateX(100%); opacity: 0; }           // step 2's home side: right
// going back sends step 1 to its left home and step 2 back to the right — direction flips
#wiz-2:checked ~ .wiz__window .wiz__panel--1 { transform: translateX(-100%); opacity: 0; }
#wiz-2:checked ~ .wiz__window .wiz__panel--2 { transform: translateX(0);     opacity: 1; }
#wiz-1:checked ~ .wiz__window .wiz__panel--1 { transform: translateX(0);     opacity: 1; }

09Diagonal scene swap

Two panels crossing the frame diagonally slide past in the same direction, one stepping in a beat behind the other, and sweep away to uncover the next scene hidden behind them in one motion. Season or campaign scenes on a landing page can change dramatically without a single reload.

skew 판 translate장면 이중 겹침transition-delay: 100ms
.scene__wipe {
  top: -20%; bottom: -20%; left: -45%;
  width: 190%;
  transform: skewX(-14deg) translateX(-115%);       // a panel laid diagonally
  transition: transform $duration $easing;
}
#scene-swap:checked ~ .scene__frame .scene__wipe { transform: skewX(-14deg) translateX(115%); }
.scene__inner { transition: opacity $dur-quick linear calc(#{$duration} / 2); }  // swap at midpoint

Where does it break — one trap

The first version of the fly-to-cart dot clearly moved, but it landed somewhere off target. I had eyeballed the distance from the card to the cart and typed translateX(247px); measuring the real coordinates with Playwright showed the badge center sat farther right than expected, and the dot was vanishing into thin air 26px short of it. Remeasuring both centers with getBoundingClientRect and correcting to translateX(273px) and translateY(-71px) made the dot land dead center on the badge. The same inspection caught the pseudo-element that draws the basket handle: it was anchored to the wrong parent and floating loose in a corner of the stage, fixed with one position: relative line. Flight animations should never be aimed by eye — measure the coordinates. The password that unlocks these nine files is 2aq7sbjt, published only after exactly this kind of verification.

Accessibility

All nine effects turn off motion under prefers-reduced-motion: reduce and keep the final state visible. 01 shows the headline with the blinds already folded away, 02 hangs the photo straight with no swing, 03, 04, and 08 swap cards, scenes, and panels instantly with no transition, 05 seats the chip in the slot immediately, 06 keeps the dot hidden and only bumps the badge, 07 skips the tearing and removes the ticket at once, and 09 swaps the scene with no panels sweeping through. Every click target is a real radio or checkbox wired to a visible label, so keyboard and screen-reader users can operate them too, and purely decorative elements are marked aria-hidden. Why transform-based motion stays smooth is documented at MDN's transform reference, and what the reduced-motion media query means at MDN's prefers-reduced-motion page. For transitions between whole pages, see 9 CSS Page Transitions, and for tab panels, the tab menu transition collection.

FAQ

Do I really need zero lines of JavaScript?

These nine run on CSS alone. Anything click-driven hides a radio or checkbox on the page and lets CSS follow the :checked state, so they work the moment you paste them in. The React versions use useState to manage that state instead.

What do I change to drop one into my own site?

Adjust the class names of the moving parts and the distance values to match your own layout. The chip flight in 05 and the cart flight in 06 depend on where your chips, cards, and cart icon actually sit, so measure the element coordinates in your browser's developer tools and enter those numbers.

Can the View Transitions API do the same thing?

The View Transitions API is a browser feature for moments when an entire document or large region changes, not for small in-page state changes like these, and its support still varies between browsers. These nine effects use only transform and opacity so they run identically everywhere.

Enter the archive password

The password is inside this article. You will find it as you read.