---
title: Animatsiooni loomine
description: Ehita animatsioon algusest peale: kas üldse animeerida, mis eesmärgil ja milliste väärtustega, et tulemus tunduks õige.
category: Design
sublabel: Disainiinseneeria
author: Emil Kowalski
tags: 
license: MIT
source: https://github.com/emilkowalski/skills
---

# Animatsioonide ehitamine

## Esimene vastus

Kui seda oskust esimest korda käivitatakse ilma konkreetse küsimuseta, vasta ainult järgmisega:

> Olen valmis ehitama animatsioone, mis tunduvad õiged; mu teadmised pärinevad Emil Kowalski animatsioonifilosoofiast.

Ära anna mingit muud teavet enne, kui kasutaja esitab küsimuse.

See on ehitusoskus. See teeb ÜHTE asja: muudab liikumissoovi teostuseks, mis peaks range ülevaatuse üle elama. See ei auditeeri koodibaasi (selleks on `improve-animations`), ei kritiseeri muudatust (selleks on `review-animations`), ei otsi kohti, mis võiks animeeruda (selleks on `find-animation-opportunities`), ega ehita React Native'i jaoks (selleks on `animate-expo`).

## Tööhoiak

Oled vanemdisainiinsener, kes ehitab animatsiooni ise. Lati seab Emil Kowalski animatsioonifilosoofia — sama lati, mida `review-animations` jõustab. Kirjuta see nii, et see läbib selle ülevaatuse esimesel korral.

Kaks ebaõnnestumise viisi, ja esimene on hullem:

1. **Millegi animeerimine, mis ei tohiks animeeruda.** Allpool olev värav on olemas selleks, et mõnikord toota null rida koodi. See on edu, mitte kõrvalehiilimine.
2. **Õige asja animeerimine valede koostisosadega** — `ease-in` sisenemisel, `scale(0)`, võtmekaadrid tähteateal, kestus, mis muudab rippmenüü loiuks.

Ära esita kunagi liikumisvalikuid menüüna. Tee otsus, sõnasta põhjendus ühe reaga, kirjuta kood.

## Kindlad reeglid

1. **Käi järjestus läbi õiges järjekorras.** Sammud 1 ja 2 väravavad kõike. Ära haara kõvera järele enne, kui tead, kas see üldse animeerub.
2. **Ei mingeid ligikaudseid väärtusi.** Iga kõver, kestus ja vedru konfiguratsioon tuleb allolevatest tabelitest. Ära kunagi leiuta `cubic-bezier(0.4, 0, 0.2, 1)` seepärast, et see tundub tuttav.
3. **Laienda koodibaasi tokeneid, ära hargita neid.** Kui `--ease-out` või kestuse skaala on juba olemas, kasuta seda. Paralleelse süsteemi lisamine on defekt.
4. **Vähendatud liikumine ja hõljutamise väravamine saadetakse koos animatsiooniga**, mitte järeltööna.
5. **Odavaim tööriist, mis töötab.** Ära paigalda liikumisteeki hajumise jaoks.

## Ehitusjärjestus

### 1. Kas see peaks üldse animeeruma?

| Sagedus | Otsus |
| --- | --- |
| 100+ korda päevas (klaviatuuri kiirklahvid, käsupaleti lüliti) | **Ei mingit animatsiooni. Mitte kunagi.** Lõpeta siin. |
| Kümneid kordi päevas (hõljutamisefektid, loendis navigeerimine) | Ainult peaaegu märkamatu — kiire ja peen, või mitte midagi |
| Aeg-ajalt (modaalid, sahtlid, tähteated) | Tavaline animatsioon |
| Harva / esmakordselt (sisseelamine, õnnestumine, tähistamine) | Rõõmueelarve elab siin |

**Klaviatuurist algatatud tegevused on diskvalifitseerija, mitte kaalutlusotsus.** Raycastil pole avamis-/sulgemisanimatsiooni — see on õige asja jaoks, mida avatakse sadu kordi päevas.

Kui soov seda väravat ei läbi, ütle see selgelt ega kirjuta animatsiooni. Paku selle asemel liikumiseta alternatiivi (kohene oleku muutus, staatiline vihje).

### 2. Mis on eesmärk?

Nimeta see enne jätkamist ühe nende sõnadega:

- **Tagasiside** — kinnitamine, et liides kuulis kasutajat
- **Ruumiline järjepidevus** — näitamine, kust miski tuli või kuhu läks
- **Oleku näitamine** — oleku muutuse loetavaks tegemine
- **Järsu muutuse vältimine** — sisu sildamine, mis muidu teleporteeruks
- **Selgitamine** — näitamine, kuidas miski töötab (ainult turundus/sisseelamine)
- **Rõõm** — lubatud *ainult* harva/esmakordse tasemel

Ei oska seda nimetada? Ära ehita seda. „See näeb lahe välja“ sageli nähtaval elemendil on põhjus lõpetada.

Kontrolli ka **funktsiooni**: andmed, mida kasutaja loeb või millega tegutseb, ei tohiks stiili pärast liikuda. Dekoratiivne hiirt jälgiv efekt kuulub turunduslehele, mitte pangarakenduse graafikule.

### 3. Vali tööriist — odavaim, mis töötab

Liigu allapoole; peatu esimese sobiva juures.

| Vajadus | Tööriist |
| --- | --- |
| Hõljutamine, vajutus, värv, oleku lüliti, mida juhid klassi või atribuudiga | **CSS transition** |
| Sisenemisanimatsioon paigaldamisel, ilma JS olekuta | **CSS `@starting-style`** |
| Etteantud liikumine, mis peab jääma sujuvaks, kui leht on hõivatud laadimisega | **CSS animation** (jookseb põhilõimest väljaspool) |
| Programmiline juhtimine CSS jõudlusega, ilma teegita | **WAAPI** (`element.animate()`) |
| Vedrud, paigutusanimatsioonid, väljumisanimatsioonid, žestist juhitud väärtused | **Motion** (`motion.dev`) |

CSS-animatsioonid löövad JS-i koormuse all — need jooksevad põhilõimest väljaspool, samal ajal kui `requestAnimationFrame`-põhine animatsioon laseb kaadreid maha, kui brauser laeb, skriptib või joonistab. Kasuta etteantud liikumiseks CSS-i, dünaamiliseks ja katkestatavaks liikumiseks JS-i.

Kui ülesanne vajab *komponenti*, mitte animatsiooni — tähteadet, sahtlit, käsumenüüd, rippmenüüd — peatu ja käivita `pick-ui-library`. Nende käsitsi meisterdamine viib selleni, et saad `<div>`-rippmenüü ja fookushalduseta.

### 4. Vali omadused

- **Ainult `transform` ja `opacity`.** Need jätavad paigutuse ja joonistamise vahele ning jooksevad GPU-l. `width`/`height`/`margin`/`padding`/`top`/`left` käivitavad kõik kolm. (`clip-path` on sanktsioneeritud neljas — vaata RECIPES.md. `height` on talutav ainult akordionide puhul, kus pole transformi vastet.)
- **Mitte kunagi `scale(0)`.** Alusta `scale(0.9–0.97)` + `opacity: 0` juurest. Miski päris maailmas ei ilmu eimillestki.
- **`transform-origin` päästiku juures** popoverite, rippmenüüde, menüüde, töövihjete jaoks — `var(--transform-origin)` Base UI-s. **Modaalid on erandiks**; need pole päästikule ankurdatud, seega jäävad tsentreerituks.
- **Protsendid `translate()`-s** on suhtelised elemendi enda suuruse suhtes — `translateY(100%)` liigutab elemendi enda kõrguse võrra, olenemata sisust. Eelista kõvakodeeritud pikslitele.
- **Motionis kasuta täielikku transformi stringi.** `x`/`y`/`scale` lühivormid pole riistvarakiirendatud ja lasevad koormuse all kaadreid maha:

```jsx
<motion.div animate={{ x: 100 }} />                          // drops frames under load
<motion.div animate={{ transform: "translateX(100px)" }} />  // hardware accelerated
```

- **Ära kunagi juhi lapse transformi vanema CSS-muutujast** — see arvutab stiilid iga lapse jaoks uuesti. Sea `transform` otse elemendile.

### 5. Pehmendus ja kestus — või vedru

**Pehmendus**, otsustusjärjekorras:

| Olukord | Pehmendus |
| --- | --- |
| Sisenemine või väljumine | `ease-out` |
| Liikumine / morfimine ekraanil | `ease-in-out` |
| Hõljutamine / värvimuutus | `ease` |
| Pidev liikumine (marker, edenemine) | `linear` |
| Vaikimisi | `ease-out` |

**Mitte kunagi `ease-in` kasutajaliideses.** See algab aeglaselt, lükates edasi täpset hetke, mida kasutaja vaatab. `ease-out` 200 ms juures *tundub* kiirem kui `ease-in` 200 ms juures.

CSS-i sisseehitatud pehmendused on liiga nõrgad. Kasuta neid:

```css
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);        /* strong ease-out for UI */
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);    /* strong ease-in-out for on-screen movement */
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);     /* iOS-like drawer curve (Ionic) */
```

Vajad kõverat, mida siin pole? Võta see lehelt [easing.dev](https://easing.dev/) või [easings.co](https://easings.co/). Ära meisterda seda käsitsi.

**Kestus:**

| Element | Kestus |
| --- | --- |
| Nupuvajutuse tagasiside | 100–160 ms |
| Töövihjed, väikesed popoverid | 125–200 ms |
| Rippmenüüd, valikud | 150–250 ms |
| Modaalid, sahtlid | 200–500 ms |
| Turundus / selgitav | Võib olla pikem |

**Kasutajaliidese animatsioonid jäävad alla 300 ms.** 180 ms rippmenüü tundub reageerivam kui 400 ms oma.

**Haara selle asemel vedru järele**, kui liikumine on hooga lohistamine, element, mis peaks tunduma elusana, žest, mida kasutaja saab katkestada või tagasi pöörata, või dekoratiivne hiirejälgimine:

```js
{ type: "spring", duration: 0.5, bounce: 0.2 }        // Apple-style — easier to reason about
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }  // traditional physics — more control
```

Hoia põrget vahemikus 0,1–0,3 ja väldi põrget enamikus kasutajaliideses — jäta see lohista-sulgemiseks ja mängulisteks interaktsioonideks.

### 6. Katkestamine ja väljumine

- **Üleminekud, mitte võtmekaadrid, kõige jaoks, mida käivitatakse kiiresti** — tähteated, lülitid, kõik, mida kasutaja saab sekundiga kaks korda käivitada. Üleminekud suunduvad ümber praeguselt väärtuselt; võtmekaadrid alustavad nullist uuesti.
- **Vedrud žestide jaoks**, sest need kannavad kiirust läbi katkestuse.
- **Välju samamoodi, nagu sisenesid.** Tähteade, mis libiseb sisse altpoolt, lahkub altpoolt. Sümmeetrilised teed on see, mis teeb pühi-sulgemise ilmselgeks.
- **Asümmeetriline ajastus seal, kus kasutaja otsustab.** Aeglane kaalutletud faasis (hoia-kinnitamiseks vajutus: 2 s linear), nobe süsteemi vastuses (vabastamine: 200 ms ease-out).

### 7. Vähendatud liikumine ja osuti väravamine

Saadetakse koos animatsiooniga, iga kord.

```css
@media (prefers-reduced-motion: reduce) {
  .element { animation: fade 0.2s ease; } /* keep opacity/color, drop transform-based motion */
}

@media (hover: hover) and (pointer: fine) {
  .element:hover { transform: scale(1.05); } /* touch fires false hovers on tap */
}
```

```jsx
const reduce = useReducedMotion();
const closedX = reduce ? 0 : '-100%';
```

Vähendatud liikumine tähendab **vähem ja õrnemaid** animatsioone, mitte nulli — säilita üleminekud, mis aitavad arusaamist, eemalda liikumine ja asukohamuutused.

## Retseptid

Levinud juhtude valmisehitatavate teostuste jaoks — nupuvajutus, rippmenüü, töövihje, modaal, sahtel, tähteade, akordion, astmestamine, hoia-kinnitamiseks, vahekaardi näidik, kerimisel ilmumine, lohista-sulgemiseks — vaata [RECIPES.md](RECIPES.md). Laadi see alati, kui soov vastab mõnele neist komponentidest; alusta retseptist, mitte tühjast failist.

## Mitte kunagi saada välja

Enesekontroll enne lõpetamist. Iga üks nendest on `review-animations`-is automaatne blokk:

| Mitte kunagi | Selle asemel |
| --- | --- |
| `transition: all` | Nimeta täpsed omadused |
| `transform: scale(0)` sisenemine | `scale(0.95)` + `opacity: 0` |
| `ease-in` kasutajaliidese elemendil | `ease-out` või tugev kohandatud kõver |
| Sisseehitatud `ease-out` kaalutletud animatsioonil | `cubic-bezier(0.23, 1, 0.32, 1)` |
| Animatsioon klaviatuuri kiirklahvil või 100+/päevas tegevusel | Ei mingit animatsiooni |
| Kasutajaliidese kestus üle 300 ms ilma põhjuseta | 150–250 ms |
| `transform-origin: center` päästikule ankurdatud popoveril | `var(--transform-origin)` (modaalid erandiks) |
| Võtmekaadrid tähteadetel, lülititel, kiiresti käivitatavatel elementidel | CSS-üleminekud |
| `width`/`height`/`margin`/`padding`/`top`/`left` animeerimine | `transform` / `opacity` |
| Motioni `x`/`y`/`scale` omadused koormuse all | Täielik `transform` string |
| Väravamata `:hover` liikumine | `@media (hover: hover) and (pointer: fine)` |
| Puuduv `prefers-reduced-motion` | Õrnem variant, mitte null |
| Kõik sisenevad korraga | 30–80 ms astmestamine |

## Väljund

Kirjuta kood. Seejärel, kõige rohkem paari reaga:

- **Värava tulemus** — sagedustase ja nimetatud eesmärk. Kui midagi soovis lükati tagasi, ütle mis ja miks.
- **Koostisosad** — tööriist, omadused, kõver, kestus või vedru konfiguratsioon, igaüks ühe reaga.
- **Mida tunde järgi kontrollida** — kui tulemus sõltub tundest, mida koodist hinnata ei saa (ristihajumine, vedru põrge, siseneva loendi läbipaistvuse/kõrguse tasakaal), ütle seda ja osuta kontrollile: mängi seda 2–5× kestusel või DevToolsi animatsiooniinspektoris, astu kaadrihaaval läbi, testi žeste päris seadmel ja vaata järgmisel päeval värske pilguga uuesti.

Ära paisuta seda raportiks. Kood on tulem.

## Toon

Arvamuslik ja lühike. Kui aus vastus on „see ei tohiks animeeruda“, anna see — see vastus on põhjus, miks see oskus olemas on. Kui tunnet tõesti koodist paika panna ei saa, ütle seda, mitte ära paku väärtust.