Mundarija (38)
- Bu darsda
- 1. Nega bu kerak?
- 2. Birinchi animatsiya: element.animate()
- 2.1 Ikki argument
- 2.2 «Bahor»: savat sakraydi
- 2.3 Keyframe'larni yozishning ikki shakli
- 3. Sozlamalar (options)
- 3.1 Asosiylari
- 3.2 fill: tugagach nima bo'ladi
- 4. Pult: Animation obyekti
- 4.1 Metodlar va xususiyatlar
- 4.2 O'zingiz boshqaring
- 5. finished: tugashini kutish
- 5.1 Promise bilan ketma-ketlik
- 5.2 cancel() va AbortError
- 6. getAnimations(): CSS animatsiyalarini ham boshqarish
- 6.1 Bitta dvigatel
- 6.2 «Bahor»: hamma narsani to'xtatish
- 6.3 CSS animatsiyasi tugashini kutish
- 7. View Transitions — JavaScript tomoni
- 7.1 startViewTransition qaytaradigan obyekt
- 7.2 ready + animate(): bosilgan joydan tarqaladigan doira
- 7.3 skipTransition() va harakatni kamaytirish
- 8. WAAPI, CSS va rAF: qaysi biri qachon
- 9. Ko'p uchraydigan xatolar
- 9.1 Kebab-case xususiyat nomi
- 9.2 Davomiylik soniyada
- 9.3 fill: "forwards" ni "yakuniy holat" deb ishlatish
- 9.4 finished ni try/catch siz kutish
- 9.5 Harakatni kamaytirishni unutish
- 10. Mashqlar
- 1-mashq (oson): «Yoqdi» tugmasi
- 2-mashq (o'rta): Ketma-ket paydo bo'lish
- 3-mashq (qiyin): Toastni yopish tugmasi
- 4-mashq: Amaliy tajriba — yangi vazifa "yonib" chiqsin
- 11. Real ishda
- Xulosa
- Manbalar
JavaScript Web Animations API: element.animate() bilan animatsiyani boshqarish
Qisqacha: Web Animations API — CSS animatsiyasini JavaScript'dan yaratish va boshqarish usuli.
element.animate(keyframes, options)animatsiyani darhol boshlaydi vaAnimationobyektini qaytaradi: u bilan pauza qilish, orqaga aylantirish, tezlikni o'zgartirish vaawait animation.finishedbilan tugashini kutish mumkin. Animatsiya CSS'dagidek brauzer ichida ishlaydi,transformvaopacityesa asosiy thread band bo'lsa ham silliq qoladi.
Bu darsda
element.animate()bilan keyframe'lar va sozlamalar (duration,easing,iterations,fill) beriladigan animatsiya yoza olasiz.Animationobyektini boshqarasiz:play,pause,reverse,cancel,finish,playbackRate,currentTime.finishedpromise bilan "animatsiya tugagach — keyingi ish" ketma-ketligini qurasiz.getAnimations()bilan CSS animatsiyalarini ham topib boshqara olasiz.document.startViewTransition()ning JavaScript tomonini —ready,finished,skipTransition()— ishlata olasiz.
Oldin bilishingiz kerak: @keyframes va animation xususiyatlari, View Transitions, requestAnimationFrame, matchMedia va foydalanuvchi sozlamalari, async / await.
1. Nega bu kerak?
«Bahor» menyusida har taom kartasida «Savatga» tugmasi bor. Jasur aka shunday xohlaydi: tugma bosilganda savat belgisi biroz "sakrasin" — mehmon taom qo'shilganini sezsin.
Sardor @keyframes darsidagi bilim bilan yozdi: CSS'da .bounce klassi va animatsiya. JavaScript esa bosishda klassni qo'shadi. Birinchi bosish ishladi. Ikkinchisi — yo'q: klass allaqachon turibdi, brauzer "hech narsa o'zgarmadi" deb animatsiyani qayta boshlamaydi. Sardor animationend da klassni olib tashlaydigan kod qo'shdi. Keyin tez-tez bosilganda animatsiya o'rtada uzilib qolishini ko'rdi.
Muammo shundaki, CSS animatsiyasi holat bilan boshqariladi: klass bor — animatsiya bor. "Hozir boshla", "to'xta", "orqaga qayt", "tugadimi?" degan buyruqlar yo'q. Ularni klasslar bilan taqlid qilish kerak bo'ladi.
requestAnimationFrame darsida boshqa yo'lni ko'rdik: har kadrda qiymatni o'zimiz hisoblaymiz. Lekin u har kadrda JavaScript'ni ishga tushiradi. Oddiy "sakrash" uchun bu ortiqcha.
O'rtadagi yo'l — Web Animations API (qisqasi WAAPI). U CSS animatsiyasining dvigatelini JavaScript'ga ochadi. Animatsiyani bitta qatorda boshlaysiz, qolganini brauzer o'zi chizadi. Qo'lingizda esa pult qoladi.
2. Birinchi animatsiya: element.animate()
2.1 Ikki argument
Sintaksis:
const animation = element.animate(keyframes, options);keyframes— keyframe'lar (kalit kadrlar): animatsiya qaysi holatlardan o'tadi. Bu CSS'dagi@keyframesichidagifrom,50%,tobloklarining JavaScript ko'rinishi.options— sozlamalar: davomiyligi, tezlanish egri chizig'i, necha marta takrorlanishi.- Qaytgan qiymat —
Animationobyekti, ya'ni o'sha "pult".
Chaqirilgan zahoti animatsiya boshlanadi. Klass qo'shish, animationend kutish, klassni olib tashlash — hech biri kerak emas.
2.2 «Bahor»: savat sakraydi
Tugmani bir necha marta, tez-tez bosib ko'ring:
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
.bar { display: flex; align-items: center; gap: 1rem; }
.cart { font-size: 2.5rem; display: inline-block; }
.count { font: 700 1.25rem/1 ui-monospace, monospace; }
button { font: inherit; padding: 0.4rem 0.8rem; }
</style>
<div class="bar">
<span class="cart" id="cart" aria-hidden="true">🛒</span>
<span class="count" id="count">0</span>
<button id="add" type="button">Oshni savatga</button>
</div>
<script>
const cart = document.getElementById("cart");
const count = document.getElementById("count");
let items = 0;
document.getElementById("add").addEventListener("click", () => {
items++;
count.textContent = items;
cart.animate(
[
{ transform: "translateY(0) scale(1)" },
{ transform: "translateY(-12px) scale(1.15)" },
{ transform: "translateY(0) scale(1)" },
],
{ duration: 300, easing: "ease-out" },
);
});
</script>Qatorma-qator:
- Birinchi argument — uchta keyframe'li ro'yxat: joyida → 12 px yuqorida va biroz katta → yana joyida. Keyframe'lar orasida brauzer o'zi oraliq kadrlarni chizadi.
duration: 300— davomiyligi millisekundda (CSS'da0.3syozardik, bu yerda faqat son).easing: "ease-out"— tezlanish: boshida tez, oxirida sekin. CSS'dagi qiymatlarning hammasi ishlaydi:ease-in-out,cubic-bezier(...),steps(4),linear(...).
Har bosish yangi animatsiya yaratadi va u eski animatsiyaning ustidan, boshidan boshlanadi. Klasslar bilan bo'lgan muammo yo'q. Biz tekshirdik: tugma uch marta bosilganda hisoblagich 3 ni ko'rsatdi va konsolda bitta ham xato chiqmadi.
Maslahat: Animatsiya faqat bezak — u tugamasa ham ma'lumot to'g'ri bo'lishi kerak. Shuning uchun
count.textContentanimatsiyadan oldin, o'zi alohida yangilanadi.
2.3 Keyframe'larni yozishning ikki shakli
Yuqoridagi shakl — obyektlar ro'yxati: har obyekt bitta kadr. Ikkinchi shakl — bitta obyekt, har xususiyatga qiymatlar ro'yxati:
// 1-shakl: kadrlar ro'yxati
card.animate(
[{ opacity: 0, transform: "scale(0.9)" },
{ opacity: 1, transform: "scale(1)" }],
400,
);
// 2-shakl: xususiyat → qiymatlar
card.animate(
{ opacity: [0, 1], transform: ["scale(0.9)", "scale(1)"] },
400,
);Ikkalasi bir xil animatsiya. Ikkinchi argument bu yerda shunchaki son — bu { duration: 400 } ning qisqa yozuvi.
Yana uch qoida:
- Xususiyat nomlari camelCase'da:
backgroundColor,borderRadius— xuddielement.style.backgroundColordagi kabi (classListva stillar darsi). Qiymatlar esa CSS'dagidek satr:"translateX(10px)","#2e7d32". offset— kadrning vaqtdagi o'rni (0 dan 1 gacha), CSS'dagi foiz o'rniga:{ opacity: 1, offset: 0.8 }— "80% da".- Bitta kadr ham yetadi.
box.animate({ transform: "scale(1.5)" }, 200)— brauzer boshlang'ich holatni elementning hozirgi uslubidan oladi. Chrome 154 dagetKeyframes()ham bitta kadr qaytardi.
Tekshirib ko'ring:
card.animate({ opacity: [0, 1] }, 0.5)yozildi. Animatsiya qancha davom etadi?
Javob
0,5 millisekund — ya'ni ko'zga ko'rinmaydi. Ikkinchi argument son bo'lsa, u millisekund. CSS'dagi 0.5s ni ko'chirganda shu xato tez-tez uchraydi. To'g'risi — 500.
3. Sozlamalar (options)
3.1 Asosiylari
| Sozlama | Ma'nosi | CSS'dagi juft |
|---|---|---|
duration |
davomiyligi, ms | animation-duration |
easing |
tezlanish egri chizig'i | animation-timing-function |
delay / endDelay |
boshidan oldin / oxiridan keyin kutish, ms | animation-delay |
iterations |
necha marta (Infinity — cheksiz) |
animation-iteration-count |
direction |
"normal", "reverse", "alternate" |
animation-direction |
fill |
tugagach holat qoladimi | animation-fill-mode |
Yana biri — id: animatsiyaga nom. Keyin uni getAnimations() ro'yxatida topish oson.
Masalan, «Bahor» logotipidagi choynakdan bug' cheksiz "nafas oladi":
steam.animate(
{
opacity: [0.3, 1],
transform: ["translateY(0)", "translateY(-6px)"],
},
{ duration: 1200, iterations: Infinity, direction: "alternate",
easing: "ease-in-out", id: "steam" },
);alternate — bir marta oldinga, bir marta orqaga. Shuning uchun bug' sakramaydi, silliq tebranadi.
3.2 fill: tugagach nima bo'ladi
Sukut bo'yicha animatsiya tugagach element avvalgi uslubiga qaytadi. opacity 1 dan 0 ga borsa, oxirida element yana ko'rinib qoladi. Bu CSS'dagi bilan bir xil.
fill: "forwards" oxirgi kadrni ushlab turadi. Oson yechimga o'xshaydi, lekin tuzog'i bor. Biz Chrome 154 da sinadik: opacity ni fill: "forwards" bilan 0.2 ga olib bordik, keyin box.style.opacity = "1" yozdik. Ekrandagi qiymat baribir 0.2 qoldi. Animatsiya uslubdan ustun turadi va u hali ham "tirik".
To'g'ri yo'l — yakuniy holatni o'zingiz yozish:
// ✅ 1-usul: avval yakuniy uslub, keyin animatsiya
toast.style.opacity = "0";
toast.animate({ opacity: [1, 0] }, 300);
// ✅ 2-usul: tugagach animatsiya qiymatini uslubga "muhrlash"
const anim = toast.animate(
{ opacity: [1, 0] },
{ duration: 300, fill: "forwards" },
);
await anim.finished;
anim.commitStyles(); // hozirgi qiymat → style atributi
anim.cancel(); // animatsiya o'chadi, uslub qoladicommitStyles() — animatsiyaning shu paytdagi qiymatlarini elementning style atributiga yozadi. Keyin cancel() animatsiyani olib tashlaydi. Sinovda shundan keyin getAnimations() bo'sh ro'yxat qaytardi, opacity esa 0.2 da qoldi — endi u oddiy uslub va uni o'zgartirsa bo'ladi.
Maslahat: Bitta xususiyatga
fill: "forwards"li animatsiyalarni ketma-ket ko'p qo'ysangiz, Chrome eskilarini o'zi tozalaydi. Yangisi eskisini to'liq yopsa, eskisi o'chiriladi (replaceState: "removed"). Sinovda uchta shunday animatsiyadan keyin ro'yxatda bittasi qoldi.
4. Pult: Animation obyekti
4.1 Metodlar va xususiyatlar
animate() qaytargan obyekt bilan:
pause()— to'xtatib turish,play()— davom ettirish.reverse()— yo'nalishni teskari qilish (yarmida bo'lsa, o'sha joydan orqaga ketadi).finish()— darhol oxiriga sakrash,cancel()— butunlay bekor qilish va boshlang'ich holatga qaytish.playbackRate— tezlik:2— ikki baravar tez,0.5— sekin,-1— orqaga.currentTime— animatsiyaning qaysi millisekundida turgani. Uni o'qish ham, yozish ham mumkin.playState— holat:"running","paused","finished"yoki"idle".
Holatlar orasidagi o'tishlar:
stateDiagram-v2
[*] --> running: animate()
running --> paused: pause()
paused --> running: play()
running --> finished: vaqt tugadi yoki finish()
finished --> running: play() yoki reverse()
running --> idle: cancel()
paused --> idle: cancel()
finished --> idle: cancel()Nimaga qarang: finished oxirgi holat emas — play() yoki reverse() uni qaytadan ishga tushiradi. idle esa "animatsiya yo'q": element boshlang'ich uslubida.
4.2 O'zingiz boshqaring
Osh tayyorlanish chizig'i 4 soniyada to'ladi. Tugmalar va surgich bilan boshqaring:
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
.track { height: 1rem; background: #eef3ee; border-radius: 1rem;
overflow: hidden; }
#bar { height: 100%; background: #2e7d32; border-radius: 1rem;
transform-origin: left; transform: scaleX(0); }
.controls { display: flex; flex-wrap: wrap; gap: 0.5rem;
margin: 0.75rem 0; }
button { font: inherit; padding: 0.4rem 0.8rem; }
input { width: 100%; }
</style>
<p>Osh tayyorlanmoqda… <output id="state">running</output></p>
<div class="track"><div id="bar"></div></div>
<div class="controls">
<button id="play" type="button">Davom</button>
<button id="pause" type="button">Pauza</button>
<button id="reverse" type="button">Orqaga</button>
<button id="fast" type="button">×2 tezlik</button>
<button id="finish" type="button">Tugat</button>
</div>
<label for="time">Vaqt (ms):</label>
<input id="time" type="range" min="0" max="4000" value="0">
<script>
const stateOut = document.getElementById("state");
const timeInput = document.getElementById("time");
const animation = document.getElementById("bar").animate(
{ transform: ["scaleX(0)", "scaleX(1)"] },
{ duration: 4000, fill: "forwards" },
);
function show() {
stateOut.textContent = animation.playState;
timeInput.value = animation.currentTime;
requestAnimationFrame(show);
}
requestAnimationFrame(show);
const actions = {
play: () => animation.play(),
pause: () => animation.pause(),
reverse: () => animation.reverse(),
fast: () => { animation.playbackRate *= 2; },
finish: () => animation.finish(),
};
for (const [id, action] of Object.entries(actions)) {
document.getElementById(id).addEventListener("click", () => {
action();
// tezlik keyingi kadrda o'zgaradi — ready kutiladi
animation.ready.then(() => {
const { playState, playbackRate } = animation;
console.log(`${id}: ${playState}, tezlik ${playbackRate}`);
});
});
}
timeInput.addEventListener("input", () => {
animation.pause();
animation.currentTime = Number(timeInput.value);
});
</script>Nimani ko'rasiz:
- «Pauza» — chiziq to'xtaydi, holat
paused. «Davom» — davom etadi. - «Orqaga» — chiziq shu joyidan bo'shay boshlaydi. Ichkarida
playbackRateishorasi almashadi: konsoldatezlik -1. - «×2 tezlik» — ikki baravar tez. Ikki marta bossangiz — to'rt baravar.
- Surgichni sursangiz, animatsiya pauzaga o'tadi va siz uni qo'lda "aylantirasiz". Video pleyerdagi kabi — bu
currentTimega yozish.
Bu yerda fill: "forwards" o'rinli: chiziq tugagach to'la qolishi kerak va biz unga boshqa uslub yozmaymiz.
Biz bosib sinadik: «Pauza» → pause: paused, tezlik 1, «Orqaga» → reverse: running, tezlik -1, «Tugat» → finish: finished, tezlik -1. Oxirgisiga e'tibor bering: orqaga ketayotgan animatsiyada finish() uni boshiga — bo'sh chiziqqa — olib boradi. "Oxir" — yo'nalishga qarab.
show funksiyasi rAF bilan har kadrda holatni ko'rsatadi. Animatsiyaning o'zi esa rAF'siz ishlaydi — uni brauzer chizadi.
Konsolga yozishdan oldin nega animation.ready kutiladi? reverse() va play() tezlikni darhol emas, keyingi kadrda almashtiradi. Biz avval ready siz yozib ko'rdik: «Orqaga» dan keyin konsolda hali eski tezlik 1 chiqdi. ready — "kutayotgan o'zgarishlar kuchga kirdi" degan promise.
Tekshirib ko'ring: Animatsiya 4 000 ms li, hozir
currentTime1 000 da.reverse()chaqirildi. Chiziq to'liq bo'shashiga qancha vaqt kerak?
Javob
1 000 ms. reverse() animatsiyani boshidan emas, turgan joyidan orqaga yuritadi. Chiziq to'rtdan bir qismi to'lgan — shuncha vaqtda bo'shaydi.
5. finished: tugashini kutish
5.1 Promise bilan ketma-ketlik
Ko'p hollarda animatsiyadan keyin nimadir qilish kerak: xabarni o'chirish, keyingi animatsiyani boshlash, tugmani yoqish. Buning uchun Animation da finished xususiyati bor. U — Promise: animatsiya tugaganda bajariladi.
«Bahor»da buyurtma tayyor bo'lganda pastdan xabar (toast) chiqadi, 1,5 soniya turadi va yo'qoladi:
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem;
min-height: 9rem; }
.toast { position: fixed; left: 1rem; bottom: 1rem; margin: 0;
padding: 0.6rem 1rem; border-radius: 0.5rem;
background: #1b3d1f; color: #fff; }
button { font: inherit; padding: 0.4rem 0.8rem; }
</style>
<button id="ready" type="button">Buyurtma tayyor</button>
<script>
async function showToast(text) {
const toast = document.createElement("p");
toast.className = "toast";
toast.setAttribute("role", "status");
toast.textContent = text;
document.body.append(toast);
const slide = [
{ transform: "translateY(150%)", opacity: 0 },
{ transform: "translateY(0)", opacity: 1 },
];
await toast.animate(slide, { duration: 250, easing: "ease-out" })
.finished;
await toast.animate(slide, {
duration: 250, delay: 1500, direction: "reverse",
fill: "forwards",
}).finished;
toast.remove();
console.log(`Toast olib tashlandi: ${text}`);
}
document.getElementById("ready").addEventListener("click", () => {
showToast("№ 17 buyurtma tayyor — osh, 2 porsiya");
});
</script>Kod yuqoridan pastga o'qiladi: chiq → kut → 1,5 soniyadan keyin orqaga qayt → kut → o'chir. Callback'lar yo'q, xuddi async / await darsidagidek. Ikkinchi animatsiyada direction: "reverse" — o'sha keyframe'lar teskari tartibda. fill: "forwards" esa toast o'chirilguncha ko'rinmay tursin uchun: oradagi bir lahzada u qayta "miltillab" ketmasin.
Tugmani bosgach, taxminan 2 soniyada konsolda:
Toast olib tashlandi: № 17 buyurtma tayyor — osh, 2 porsiyafinished bilan bir qatorda eski uslubdagi onfinish xususiyati ham bor: anim.onfinish = () => {...}. U ham ishlaydi, lekin await bilan ketma-ketlik yozish ancha qulay.
5.2 cancel() va AbortError
Animatsiya bekor qilinsa, finished bajarilmaydi — u xato bilan rad etiladi (reject). Chrome 154 dagi xato:
AbortError: The user aborted a request.Tarjimasi: "Foydalanuvchi so'rovni to'xtatdi". Matn biroz g'alati — u AbortController darsidagi fetch xatosi bilan bir xil. Brauzer ikkalasiga bitta DOMException turini ishlatadi. Muhimi — nomi: AbortError.
Agar await anim.finished ni try/catch siz yozsangiz va animatsiya bekor qilinsa, natija oynasining konsolida shunday chiqadi:
Uncaught (in promise) AbortError: The user aborted a request.Bu ushlanmagan xato. Bekor qilinishi mumkin bo'lgan animatsiyani shunday kuting:
try {
await anim.finished;
toast.remove();
} catch (error) {
if (error.name !== "AbortError") throw error;
// bekor qilindi — hech narsa qilmaymiz
}AbortError dan boshqa xatolarni yutib yubormaymiz — ular qayta otiladi.
Tekshirib ko'ring: Toast chiqib turganda foydalanuvchi uni yopish tugmasini bosdi va kod
anim.finish()chaqirdi.await anim.finisheddan keyingitoast.remove()bajariladimi?anim.cancel()bo'lsa-chi?
Javob
finish() — ha: animatsiya darhol oxiriga yetadi va finished bajariladi. cancel() — yo'q: finished AbortError bilan rad etiladi, remove() ga navbat kelmaydi (catch'ga o'tadi). Toastni yopish uchun finish() to'g'riroq.
6. getAnimations(): CSS animatsiyalarini ham boshqarish
6.1 Bitta dvigatel
WAAPI CSS animatsiyalari bilan bitta dvigatelda ishlaydi. Shuning uchun CSS'da yozilgan @keyframes animatsiyasi va transition ham JavaScript'dan Animation obyekti bo'lib ko'rinadi.
element.getAnimations()— shu elementdagi barcha faol animatsiyalar.document.getAnimations()— butun sahifadagilar.
CSS animatsiyasi CSSAnimation turida keladi va unda animationName bor, transition esa CSSTransition turida, transitionProperty bilan. Ikkalasida ham pause(), playbackRate, finished — hammasi bor.
6.2 «Bahor»: hamma narsani to'xtatish
Sahifada CSS bilan aylanuvchi yuklanish belgisi va JS bilan "nafas oluvchi" bug' bor. Bitta tugma hammasini to'xtatadi:
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
.row { display: flex; align-items: center; gap: 1.5rem;
margin-bottom: 1rem; }
.spinner { width: 2rem; height: 2rem; border-radius: 50%;
border: 4px solid #cfe3cf; border-top-color: #2e7d32;
animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(1turn); } }
#steam { font-size: 2rem; }
button { font: inherit; padding: 0.4rem 0.8rem; }
</style>
<div class="row">
<div class="spinner" aria-hidden="true"></div>
<span id="steam" aria-hidden="true">♨️</span>
</div>
<button id="toggle" type="button" aria-pressed="false">
Harakatni to'xtatish
</button>
<script>
document.getElementById("steam").animate(
{ opacity: [0.3, 1] },
{ duration: 900, iterations: Infinity, direction: "alternate",
id: "steam" },
);
const toggle = document.getElementById("toggle");
let paused = false;
toggle.addEventListener("click", () => {
paused = !paused;
toggle.setAttribute("aria-pressed", String(paused));
for (const animation of document.getAnimations()) {
if (paused) animation.pause();
else animation.play();
const name = animation.animationName ?? animation.id;
console.log(`${animation.constructor.name} «${name}»:`
+ ` ${animation.playState}`);
}
});
</script>Tugmani bosganingizda konsolga shu ikki qator chiqadi (bosib sinalgan):
CSSAnimation «spin»: paused
Animation «steam»: pausedanimation.animationName ?? animation.id — CSS animatsiyasida nomi @keyframes dan keladi, JS animatsiyasida esa biz bergan id dan. Bu tugma — harakatdan bezovta bo'ladigan odamlar uchun "pauza" tugmasining eng sodda ko'rinishi.
6.3 CSS animatsiyasi tugashini kutish
getAnimations() ning eng ko'p ishlatiladigan joyi — elementni CSS animatsiyasidan keyin o'chirish. Animatsiya CSS'da yozilgan bo'lsa ham, uni JavaScript'da kutish mumkin:
card.classList.add("leaving"); // CSS'da chiqish animatsiyasi
await Promise.all(
card.getAnimations().map((animation) => animation.finished),
);
card.remove();Promise.all (Promise kombinatorlari) — hamma animatsiyalar tugashini kutadi. Klassda animatsiya bo'lmasa (masalan, foydalanuvchi harakatni o'chirgan va CSS uni none qilgan), ro'yxat bo'sh bo'ladi va Promise.all([]) darhol bajariladi. Element baribir o'chadi — animationend kutib qolib ketish xavfi yo'q.
7. View Transitions — JavaScript tomoni
7.1 startViewTransition qaytaradigan obyekt
View Transitions darsida document.startViewTransition(yangila) ni ishlatgan edik: brauzer eski va yangi ko'rinishni suratga olib, ular orasida animatsiya qiladi. O'shanda "o'tish tugashini kutish va uni o'tkazib yuborish — JavaScript tomonida" degan edik.
startViewTransition ViewTransition obyektini qaytaradi. Unda uchta promise va bitta metod bor:
updateCallbackDone— siz bergan yangilash funksiyasi bajarildi (DOM o'zgardi).ready— suratlar olindi,::view-transition-…pseudo-elementlari yaratildi, animatsiya boshlanmoqda.finished— animatsiya tugadi, pseudo-elementlar o'chirildi.skipTransition()— animatsiyani o'tkazib yuborish: DOM baribir yangilanadi, faqat chiroyli o'tish bo'lmaydi.
sequenceDiagram
participant K as Kodingiz
participant B as Brauzer
K->>B: startViewTransition(update)
B->>B: eski ko'rinish surati
B->>K: update() chaqiriladi
Note over K,B: updateCallbackDone
B->>B: yangi surat, pseudo-elementlar
Note over K,B: ready — animate() shu yerda
B->>B: animatsiya
Note over K,B: finished7.2 ready + animate(): bosilgan joydan tarqaladigan doira
ready dan keyin pseudo-elementlar mavjud. Ularni WAAPI bilan animatsiya qilish mumkin. Buning uchun options da pseudoElement beriladi. Klassik misol — tema almashganda yangi rang bosilgan nuqtadan doira bo'lib tarqaladi:
<style>
:root { color-scheme: light; }
body { font: 1rem/1.5 system-ui, sans-serif; margin: 0;
padding: 1rem; min-height: 12rem; background: #fdfbf6;
color: #1d2a1f; }
body.dark { background: #16201a; color: #e9f1ea; }
button { font: inherit; padding: 0.4rem 0.8rem; }
::view-transition-old(root), ::view-transition-new(root) {
animation: none; mix-blend-mode: normal;
}
</style>
<h3>«Bahor» menyusi</h3>
<p>Osh — 35 000 so'm</p>
<button id="theme" type="button">Temani almashtirish</button>
<script>
const button = document.getElementById("theme");
button.addEventListener("click", async (event) => {
const update = () => document.body.classList.toggle("dark");
if (!document.startViewTransition) {
update();
return;
}
const transition = document.startViewTransition(update);
await transition.updateCallbackDone;
console.log("1) DOM yangilandi");
await transition.ready;
console.log("2) suratlar tayyor");
const radius = Math.hypot(innerWidth, innerHeight);
const at = `at ${event.clientX}px ${event.clientY}px`;
document.documentElement.animate(
{ clipPath: [`circle(0 ${at})`, `circle(${radius}px ${at})`] },
{ duration: 500, easing: "ease-in",
pseudoElement: "::view-transition-new(root)" },
);
await transition.finished;
console.log("3) o'tish tugadi");
});
</script>Qatorma-qator:
- CSS'dagi
animation: none— brauzerning standart "eriydigan" animatsiyasini o'chiramiz, o'rniga o'zimiznikini qo'yamiz. await transition.ready— shundan keyin::view-transition-new(root)(yangi ko'rinish surati) bor.Math.hypot(innerWidth, innerHeight)— oyna diagonali: doira butun oynani yopishi uchun yetarli radius.clipPath: circle(...)— yangi surat avval bosilgan nuqtadagi nol radiusli doira ichida ko'rinadi, keyin doira kattalashadi.pseudoElement— animatsiya elementning o'ziga emas, uning pseudo-elementiga qo'llanadi.
Bosganda konsolda:
1) DOM yangilandi
2) suratlar tayyor
3) o'tish tugadiTartib doim shunday. Biz Chrome 154 da (natija oynasida) sinadik: ready dan keyin document.getAnimations() da ::view-transition-group(root), ::view-transition-old(root) va ::view-transition-new(root) animatsiyalari bor edi.
7.3 skipTransition() va harakatni kamaytirish
prefers-reduced-motion darsida aytgandik: harakat ba'zi odamlarda bosh aylanishini qo'zg'atadi. matchMedia darsida bu sozlamani JavaScript'dan o'qishni o'rgandik. Endi uni ishlatamiz:
const reduceMotion = matchMedia("(prefers-reduced-motion: reduce)");
const transition = document.startViewTransition(update);
if (reduceMotion.matches) {
transition.skipTransition(); // DOM yangilanadi, animatsiyasiz
}skipTransition() dan keyin updateCallbackDone va finished odatdagidek bajariladi. ready esa rad etiladi — animatsiya bo'lmaydi. Chrome 154 dagi xabar:
AbortError: Transition was skipped. skipTransition() calledShuning uchun await transition.ready ni skipTransition() bilan birga ishlatsangiz — try/catch kerak. Yoki ready o'rniga finished ni kuting: u o'tkazib yuborilganda ham bajariladi.
Oddiy element.animate() uchun ham shu qoida: harakatni kamaytirish yoqilgan bo'lsa, duration: 0 bering yoki animatsiyani umuman chaqirmang. Ma'lumot (hisoblagich, tema) baribir yangilanadi.
Maslahat: Chrome 154 da
ViewTransitionobyektidatypes(o'tish turlari, View Transitions darsida ko'rganmiz) vawaitUntil()ham bor. Ular yangi va hamma brauzerda emas. Ishlatishdan oldin Baseline holatini tekshiring.
8. WAAPI, CSS va rAF: qaysi biri qachon
| Vazifa | Vosita |
|---|---|
| Hover, fokus, holat o'zgarishi | CSS transition |
| Doimiy bezak (yuklanish belgisi) | CSS @keyframes |
| Bosishga javob, qiymatlar JS'da hisoblanadi, "tugagach — keyingisi" | WAAPI |
Har kadrda JS hisoblaydigan qiymat (hisoblagich, fizika, <canvas>) |
requestAnimationFrame |
WAAPI'ning rAF'dan katta afzalligi — u brauzer ichida ishlaydi. transform va opacity animatsiyasini Chrome kompozitor thread'iga beradi. Kompozitor — tayyor chizilgan qatlamlarni surib, ustma-ust qo'yib ekranga chiqaradigan alohida thread (Rendering pipeline darsi). U JavaScript'ni kutmaydi. JavaScript 200 ms band bo'lib qolsa ham, savat silliq sakraydi. rAF animatsiyasi esa o'sha 200 ms da to'xtab turardi.
Bu afzallik faqat "arzon" xususiyatlarga tegishli. width, top, margin ni WAAPI bilan animatsiya qilsangiz ham, har kadrda layout qayta hisoblanadi — CSS'dagi kabi.
9. Ko'p uchraydigan xatolar
9.1 Kebab-case xususiyat nomi
// ❌ "background-color" — e'tiborsiz qoladi
box.animate(
[{ "background-color": "blue" }, { "background-color": "green" }],
1000,
);Xato ham, ogohlantirish ham chiqmaydi — rang shunchaki o'zgarmaydi. Chrome 154 da getKeyframes() bu kadrlarda hech qanday xususiyat qaytarmadi. Tuzatish: backgroundColor. (CSS o'zgaruvchilari esa aksincha, chiziqcha bilan yoziladi: "--angle".)
9.2 Davomiylik soniyada
animate(kadrlar, 0.3) — 0,3 ms. Tuzatish: 300.
9.3 fill: "forwards" ni "yakuniy holat" deb ishlatish
Animatsiya uslubni ushlab turadi va keyin yozilgan style ko'rinmaydi. Tuzatish: yakuniy uslubni o'zingiz yozing yoki commitStyles() + cancel().
9.4 finished ni try/catch siz kutish
Animatsiya bekor qilinsa — Uncaught (in promise) AbortError. Tuzatish: AbortError ni ushlang yoki bekor qilinishi mumkin bo'lmagan joyda kuting.
9.5 Harakatni kamaytirishni unutish
Har bosishda katta harakat — ba'zi foydalanuvchilar uchun og'riqli. Tuzatish: matchMedia("(prefers-reduced-motion: reduce)") ni tekshiring.
10. Mashqlar
1-mashq (oson): «Yoqdi» tugmasi
«Bahor» sharhlari ostida tugmasi bor. Bosilganda u 250 ms da scale(1) → scale(1.3) → scale(1) bo'lib "urib" qo'ysin va yonidagi son bittaga oshsin. «Savat sakraydi» misolidagi naqshni ishlating.
Yechim
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
#like { font-size: 1.5rem; padding: 0.3rem 0.7rem;
display: inline-block; }
</style>
<button id="like" type="button" aria-label="Yoqdi">❤</button>
<span id="likes">12</span>
<script>
const like = document.getElementById("like");
const likes = document.getElementById("likes");
like.addEventListener("click", () => {
likes.textContent = Number(likes.textContent) + 1;
like.animate(
{ transform: ["scale(1)", "scale(1.3)", "scale(1)"] },
{ duration: 250, easing: "ease-out" },
);
});
</script>Keyframe'lar ikkinchi shaklda: transform ga uchta qiymat. Son animatsiyadan oldin yangilanadi — animatsiya faqat bezak.
2-mashq (o'rta): Ketma-ket paydo bo'lish
Uchta taom kartasi (.dish) sahifa ochilganda birin-ketin paydo bo'lsin: har biri 300 ms da opacity 0 → 1 va translateY(10px) → 0. Keyingisi oldingisi tugagach boshlansin. Hammasi tugagach konsolga "Menyu tayyor" chiqsin.
Ishora: for...of ichida await card.animate(...).finished. Boshlanishdan oldin kartalar ko'rinmay tursin uchun ularga CSS'da opacity: 0 bering va animatsiyada fill: "forwards" ishlating.
Yechim
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
.dish { opacity: 0; margin: 0.4rem 0; padding: 0.5rem 0.75rem;
border: 1px solid #cfe3cf; border-radius: 0.5rem; }
</style>
<p class="dish">Osh — 35 000 so'm</p>
<p class="dish">Lag'mon — 28 000 so'm</p>
<p class="dish">Manti — 30 000 so'm</p>
<script>
async function revealMenu() {
for (const card of document.querySelectorAll(".dish")) {
await card.animate(
{ opacity: [0, 1],
transform: ["translateY(10px)", "translateY(0)"] },
{ duration: 300, easing: "ease-out", fill: "forwards" },
).finished;
}
console.log("Menyu tayyor");
}
revealMenu();
</script>Konsolda:
Menyu tayyorBu yerda fill: "forwards" kerak: CSS'dagi opacity: 0 animatsiya tugagach qaytib kelardi. Yana bir yo'l — har biriga delay: index * 300 berib, hammasini bir vaqtda boshlash. Unda Promise.all bilan oxirgisini kutasiz.
3-mashq (qiyin): Toastni yopish tugmasi
«finished: tugashini kutish» bo'limidagi toastga «×» tugmasi qo'shing. Bosilganda toast darhol (150 ms da) yo'qolsin. Kutayotgan 1,5 soniyalik yopilish animatsiyasi xato bermasin. Konsolga har holatda bitta Toast olib tashlandi: … chiqsin.
Ishora: yopilish animatsiyasini o'zgaruvchida saqlang. «×» bosilganda unga playbackRate ni oshirib, currentTime ni delay ga (1 500) suring yoki shunchaki finish() qiling. cancel() emas — u AbortError beradi.
Yechim
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem;
min-height: 9rem; }
.toast { position: fixed; left: 1rem; bottom: 1rem; margin: 0;
display: flex; gap: 0.75rem; align-items: center;
padding: 0.6rem 1rem; border-radius: 0.5rem;
background: #1b3d1f; color: #fff; }
.toast button { font: inherit; background: none; color: inherit;
border: 0; cursor: pointer; }
#ready { font: inherit; padding: 0.4rem 0.8rem; }
</style>
<button id="ready" type="button">Buyurtma tayyor</button>
<script>
async function showToast(text) {
const toast = document.createElement("p");
toast.className = "toast";
toast.setAttribute("role", "status");
const label = document.createElement("span");
label.textContent = text;
const close = document.createElement("button");
close.type = "button";
close.setAttribute("aria-label", "Yopish");
close.textContent = "×";
toast.append(label, close);
document.body.append(toast);
const slide = [
{ transform: "translateY(150%)", opacity: 0 },
{ transform: "translateY(0)", opacity: 1 },
];
const show = toast.animate(slide, { duration: 250 });
const hide = toast.animate(slide, {
duration: 250, delay: 1500, direction: "reverse",
fill: "forwards",
});
hide.pause(); // ko'rinish tugaguncha kutib tursin
await show.finished;
hide.play();
close.addEventListener("click", () => {
hide.currentTime = 1500; // kutishni o'tkazib yuboramiz
hide.playbackRate = 1.7; // 250 ms → ~150 ms
}, { once: true });
await hide.finished;
toast.remove();
console.log(`Toast olib tashlandi: ${text}`);
}
document.getElementById("ready").addEventListener("click", () => {
showToast("№ 18 buyurtma tayyor");
});
</script>Ikkala animatsiya boshida yaratiladi, yopilishi pauzada turadi. «×» bosilganda biz cancel() qilmaymiz — currentTime ni kutish oxiriga suramiz va tezlikni oshiramiz. hide.finished odatdagidek bajariladi, shuning uchun remove() va konsol qatori bitta joyda qoladi. Biz sinadik: «×» bosilgandan taxminan 0,2 soniyada konsolda Toast olib tashlandi: № 18 buyurtma tayyor chiqdi.
4-mashq: Amaliy tajriba — yangi vazifa "yonib" chiqsin
vazifalar kanon kodiga tegmasdan tajriba qiling: kurs/mashqlar/13/10-waapi/index.html — kichik forma va <ul>. Yangi qo'shilgan <li> ning foni 600 ms davomida sariq rangdan (#fff3b0) shaffofga o'tsin — "yangi qo'shildi" belgisi. Harakatni kamaytirish yoqilgan bo'lsa, animatsiya bo'lmasin. Live Server bilan oching.
Yechim
<form id="form">
<label for="text">Yangi vazifa</label>
<input id="text" required>
<button>Qo'shish</button>
</form>
<ul id="list"></ul>
<script>
const form = document.getElementById("form");
const input = document.getElementById("text");
const list = document.getElementById("list");
const reduceMotion = matchMedia("(prefers-reduced-motion: reduce)");
form.addEventListener("submit", (event) => {
event.preventDefault();
const item = document.createElement("li");
item.textContent = input.value;
list.append(item);
form.reset();
if (reduceMotion.matches) return;
item.animate(
{ backgroundColor: ["#fff3b0", "transparent"] },
{ duration: 600, easing: "ease-out" },
);
});
</script>backgroundColor — camelCase. fill kerak emas: animatsiya tugagach <li> o'zining odatiy (shaffof) foniga qaytadi — aynan kerakli holat. DevTools'da Rendering paneli → "Emulate CSS media feature prefers-reduced-motion" → reduce bilan ikkinchi holatni sinang.
git add 13/10-waapi/index.html
git commit -m "13/10: yangi vazifa WAAPI bilan ajratib ko'rsatiladi"11. Real ishda
- Mikro-interaksiyalar. "Savatga qo'shildi", "Yoqdi", nusxalandi belgisi — bosishga javob beradigan qisqa animatsiyalar WAAPI bilan bir necha qatorda yoziladi.
- Kutubxonalar. Motion (oldingi nomi Framer Motion) — React va oddiy JavaScript uchun animatsiya kutubxonasi. U imkon bo'lsa animatsiyani WAAPI'ga topshiradi — shuning uchun asosiy thread band bo'lsa ham silliq. React'ni 17-qismdan o'rganamiz, hozir bilish shart emas.
- View Transitions. Tema almashtirish, ro'yxatdan batafsil sahifaga o'tish —
startViewTransition+ready+animate(). Freymvorklar (Next.js, Astro) shu API'ni ichkarida ishlatadi. - Testlar. Animatsiyali interfeysni testlashda
getAnimations()bilan barcha animatsiyalarnifinish()qilib, natijani darhol tekshirishadi. - Intervyu. "CSS animatsiyasi, WAAPI va rAF farqi?", "Animatsiya tugashini qanday kutasiz?" — frontend intervyularida uchraydi.
Xulosa
element.animate(keyframes, options)animatsiyani darhol boshlaydi vaAnimationpultini qaytaradi.- Keyframe xususiyatlari camelCase'da, davomiylik — millisekundda.
fill: "forwards"uslubni "qulflaydi" — yakuniy holatni o'zingiz yozing yokicommitStyles()qiling.pause,play,reverse,finish,cancel,playbackRate,currentTime— to'liq boshqaruv.await animation.finished— "tugagach, keyingisi";cancel()bo'lsaAbortError.getAnimations()CSS animatsiyalarini ham qaytaradi;startViewTransitionningreadyvafinishedi bilan o'tishni JS'dan boshqarasiz.
Keyingi dars: File va Blob — brauzerda fayl bilan ishlash boshlanadi: foydalanuvchi tanlagan faylni o'qimasdan ko'rish, o'zingiz fayl yaratish va uni yuklab berish.
Manbalar
- W3C: Web Animations Level 1 — w3.org/TR/web-animations-1
- MDN:
Element.animate(),Animation,Document.getAnimations()— developer.mozilla.org - MDN:
ViewTransition(ready,finished,skipTransition) — developer.mozilla.org - Chrome for Developers: "View Transitions" (bosilgan joydan doira misoli) — developer.chrome.com
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!