Yalnızca CSS Wolfenstein birkaç hafta önce yaptığım küçük bir proje. CSS 3D dönüşümleri ve animasyonları ile bir deneydi.
Esinlenen FPS demosu ve başka Wolfenstein KoduKalem, kendi versiyonumu oluşturmaya karar verdim. Orijinal Wolfenstein 1D oyununun Bölüm 9 - Kat 3'una gevşek bir şekilde dayanmaktadır.
Editör: Bu oyun, Game Over ekranından kaçınmak için kasıtlı olarak hızlı tepki vermeyi gerektiriyor.
İşte bir oynanış videosu:
Özetle, projem özenle yazılmış uzun bir CSS animasyonundan başka bir şey değil. Ayrıca birkaç örnek onay kutusu hack.
:checked ~ div { animation-name: spin; }
Ortam 3B ızgara yüzlerinden oluşur ve animasyonlar çoğunlukla düz 3B ötelemeler ve döndürmelerdir. Hiçbir şey gerçekten süslü değil.
Bununla birlikte, çözülmesi özellikle zor olan iki sorun vardı:
- Oyuncu bir düşmana tıkladığında "silah ateşleme" animasyonunu oynatın.
- Hızlı hareket eden patron son vuruşu aldığında, dramatik bir ağır çekime girin.
Teknik düzeyde bu şu anlama geliyordu:
- Sonraki onay kutusu işaretlendiğinde bir animasyonu yeniden oynatın.
- Bir onay kutusu işaretlendiğinde bir animasyonu yavaşlatın.
Aslında, projemde hiçbiri düzgün bir şekilde çözülmedi! Ya geçici çözümler kullandım ya da vazgeçtim.
Öte yandan, biraz araştırmadan sonra sonunda her iki sorunun da anahtarını buldum: CSS animasyonlarını çalıştırmanın özelliklerini değiştirmek. Bu yazıda, bu konuyu daha ayrıntılı olarak inceleyeceğiz:
- Çok sayıda etkileşimli örnek.
- Diseksiyonlar: Her bir örnek nasıl çalışır (veya çalışmaz)?
- Sahne arkası: Tarayıcılar animasyon durumlarını nasıl işler?
İzin ver "tuğlalarımı fırlat".
Sorun 1: Animasyonu Yeniden Oynatma
İlk örnek: "sadece başka bir onay kutusu"
İlk sezgim, çalışmayan “sadece başka bir onay kutusu ekle” idi:
Her onay kutusu ayrı ayrı çalışır, ancak ikisi birlikte çalışmaz. Bir onay kutusu zaten işaretliyse diğeri artık çalışmaz.
İşte nasıl çalıştığı (veya "çalışmadığı"):
- The
animation-name
of<div>
isnone
varsayılan olarak. - Kullanıcı bir onay kutusuna tıklar,
animation-name
olurspin
, ve animasyon baştan başlar. - Bir süre sonra kullanıcı diğer onay kutusuna tıklar. Yeni bir CSS kuralı yürürlüğe girer, ancak
animation-name
is yine despin
, bu, hiçbir animasyonun eklenmediği veya kaldırılmadığı anlamına gelir. Animasyon hiçbir şey olmamış gibi oynamaya devam ediyor.
İkinci örnek: "animasyonu klonlama"
Çalışan bir yaklaşım, animasyonu klonlamaktır:
#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2; }
İşte nasıl çalışır:
animation-name
isnone
Başlangıçta.- Kullanıcı “Döndür!” seçeneğine tıklar,
animation-name
olurspin1
. Animasyonspin1
yeni eklendiği için baştan başlatılır. - Kullanıcı “Tekrar Döndür!” seçeneğine tıklar,
animation-name
olurspin2
. Animasyonspin2
yeni eklendiği için baştan başlatılır.
Adım #3'te, spin1
CSS kurallarının sırası nedeniyle kaldırıldı. “Tekrar Döndür!” durumunda çalışmaz. önce kontrol edilir.
Üçüncü örnek: “aynı animasyonu eklemek”
Başka bir çalışma yaklaşımı “aynı animasyonu eklemek”tir:
#spin1:checked ~ div { animation-name: spin; }
#spin2:checked ~ div { animation-name: spin, spin; }
Bu, önceki örneğe benzer. Aslında davranışı şu şekilde anlayabilirsiniz:
#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2, spin1; }
“Tekrar Döndür!” işaretlendiğinde, eski çalışan animasyon yeni listede sezgisel olmayan ikinci animasyon haline gelir. Doğrudan bir sonuç şudur: hile işe yaramazsa animation-fill-mode
is forwards
. İşte bir demo:
Bunun neden böyle olduğunu merak ediyorsanız, işte bazı ipuçları:
animation-fill-mode
isnone
varsayılan olarak, bu, "Oynatılmıyorsa animasyonun hiçbir etkisi yoktur" anlamına gelir.animation-fill-mode: forwards;
"Animasyon oynatıldıktan sonra, sonsuza kadar son ana karede kalmalıdır" anlamına gelir.spin1
kararı her zaman geçersizdirspin2
çünküspin1
listede daha sonra görünür.- Kullanıcının “Döndür!”e tıkladığını, tam bir dönüş için beklediğini ve ardından “Tekrar Döndür!”e tıkladığını varsayalım. Şu anda.
spin1
zaten bitti vespin2
sadece başlar.
Tartışma
Temel kural: mevcut bir CSS animasyonunu "yeniden başlatamazsınız". Bunun yerine, yeni bir animasyon eklemek ve oynatmak istiyorsunuz. Bu tarafından onaylanabilir W3C spesifikasyonu:
Bir animasyon başladıktan sonra bitene veya animasyon adı kaldırılana kadar devam eder.
Şimdi son iki örneği karşılaştırarak, pratikte "klonlama animasyonlarının", özellikle CSS ön işlemcisi mevcut olduğunda, genellikle daha iyi çalışması gerektiğini düşünüyorum.
Sorun 2: Yavaş Hareket
Bir animasyonu yavaşlatmanın yalnızca daha uzun bir süre ayarlamaktan ibaret olduğu düşünülebilir. animation-duration
:
div { animation-duration: 0.5s; }
#slowmo:checked ~ div { animation-duration: 1.5s; }
Gerçekten de, bu işe yarar:
…ya da öyle mi?
Birkaç tweaks ile sorunu görmek daha kolay olmalı.
Evet, animasyon yavaşladı. Ve hayır, iyi görünmüyor. Onay kutusunu değiştirdiğinizde köpek (neredeyse) her zaman "atlar". Ayrıca, köpek ilk pozisyondan ziyade rastgele bir pozisyona atlıyor gibi görünüyor. Nasıl olur?
İki “gölge unsur” ekleseydik bunu anlamak daha kolay olurdu:
Her iki gölge öğesi de farklı animasyonlarla aynı animasyonları çalıştırıyor. animation-duration
. Ve onay kutusundan etkilenmezler.
Onay kutusunu değiştirdiğinizde, öğe hemen iki gölge öğesinin durumları arasında geçiş yapar.
Alıntı yapmak W3C spesifikasyonu:
Animasyon çalışırken animasyon özelliklerinin değerlerinde yapılan değişiklikler, animasyonun başladığı andan itibaren bu değerlere sahipmiş gibi uygulanır.
Bu şu vatansız tarayıcıların animasyonlu değeri kolayca belirlemesini sağlayan tasarım. Gerçek hesaplama açıklanmıştır okuyun ve okuyun.
Başka Bir Deneme
Bir fikir, mevcut animasyonu duraklatmak ve ardından oradan devralan daha yavaş bir animasyon eklemektir:
div {
animation-name: spin1;
animation-duration: 2s;
}
#slowmo:checked ~ div {
animation-name: spin1, spin2;
animation-duration: 2s, 5s;
animation-play-state: paused, running;
}
Böylece çalışır:
…ya da öyle mi?
“Slowmo!”ya tıkladığınızda yavaşlar. Ancak tam bir daire beklerseniz, bir “sıçrama” göreceksiniz. Aslında, her zaman “Slowmo!” olduğunda pozisyona atlar. tıklanır.
nedeni bizde yok from
ana kare tanımlandı - ve yapmamalıyız. Kullanıcı “Slowmo!”ya tıkladığında, spin1
bir konumda duraklatılır ve spin2
tam olarak aynı pozisyonda başlar. Bu pozisyonu önceden tahmin edemeyiz… yoksa yapabilir miyiz?
Çalışan Bir Çözüm
Yapabiliriz! Özel bir özellik kullanarak, ilk animasyondaki açıyı yakalayabilir ve ardından ikinci animasyona aktarabiliriz:
div {
transform: rotate(var(--angle1));
animation-name: spin1;
animation-duration: 2s;
}
#slowmo:checked ~ div {
transform: rotate(var(--angle2));
animation-name: spin1, spin2;
animation-duration: 2s, 5s;
animation-play-state: paused, running;
}
@keyframes spin1 {
to {
--angle1: 360deg;
}
}
@keyframes spin2 {
from {
--angle2: var(--angle1);
}
to {
--angle2: calc(var(--angle1) + 360deg);
}
}
Not: @property
bu örnekte kullanılan tüm tarayıcılar tarafından desteklenmez.
“Mükemmel” Çözüm
Önceki çözüm için bir uyarı var: “yavaş moddan çıkmak” iyi çalışmıyor.
İşte daha iyi bir çözüm:
Bu versiyonda, ağır çekime sorunsuz bir şekilde girilebilir veya çıkılabilir. Herhangi bir deneysel özellik de kullanılmamaktadır. Peki mükemmel çözüm mü? Evet ve hayır.
Bu çözüm, "vites değiştirmek" gibi çalışır:
- Dişliler: iki tane var
<div>
s. Biri diğerinin ebeveynidir. Her ikisi de varspin
animasyon ama farklıanimation-duration
. Elemanın son hali, her iki animasyonun da toplanmasıdır. - Kaydırma: Başlangıçta yalnızca bir
<div>
animasyonu çalışıyor. Diğeri duraklatılır. Onay kutusu değiştirildiğinde, her iki animasyon da durumlarını değiştirir.
Sonuçtan gerçekten hoşlansam da bir sorun var: spin
genel olarak diğer animasyon türleri için çalışmayan animasyon.
Pratik Bir Çözüm (JS ile)
Genel animasyonlar için, biraz JavaScript ile ağır çekim işlevini elde etmek mümkündür:
Hızlı bir açıklama:
- Animasyon ilerlemesini izlemek için özel bir özellik kullanılır.
- Onay kutusu değiştirildiğinde animasyon "yeniden başlatılır".
- JS kodu doğru olanı hesaplar
animation-delay
sorunsuz bir geçiş sağlamak için. Ben tavsiye ediyorum Bu makale negatif değerlerine aşina değilsenizanimation-delay
.
Bu çözümü, "animasyonu yeniden başlatma" ve "vites değiştirme" yaklaşımının bir karışımı olarak görebilirsiniz.
Burada animasyonun ilerlemesini doğru bir şekilde izlemek önemlidir. Aşağıdaki durumlarda geçici çözümler mümkündür: @property
mevcut değil. Örnek olarak, bu sürüm kullanır z-index
ilerlemeyi izlemek için:
Yan not: Başlangıçta, yalnızca CSS'ye yönelik bir sürüm oluşturmaya da çalıştım ancak başarılı olamadım. %100 emin olmamakla birlikte bence animation-delay
is canlandırılabilir değil.
İşte minimum JavaScript içeren bir sürüm. Yalnızca "yavaş moda girmek" işe yarar.
Yalnızca çalışan bir CSS sürümü oluşturmayı başarırsanız lütfen bana bildirin!
Ağır Çekim Herhangi Bir Animasyon (JS ile)
Son olarak, birden fazla karmaşık animasyonda bile (neredeyse) herhangi bir animasyon için işe yarayan bir çözümü paylaşmak istiyorum. @keyframes
:
Temel olarak, bir animasyon ilerleme izleyicisi eklemeniz ve ardından dikkatlice hesaplamanız gerekir. animation-delay
yeni animasyon için Ancak bazen doğru değerleri elde etmek zor (ama mümkün) olabilir.
Örneğin:
animation-timing-function
değillinear
.animation-direction
değilnormal
.- birden çok değer
animation-name
farklı olananimation-duration
's veanimation-delay
Var.
Bu yöntem de açıklanmıştır okuyun için Web Animasyonları API'sı.
Teşekkürler
Yalnızca CSS projeleri ile karşılaştıktan sonra bu yola başladım. Bazıları hassas sanat eseri, ve bazıları karmaşık mekanizmalar. Benim favorilerim 3B nesneler içerenler, örneğin bu top zıplatma ve bu ambalaj küpü.
Başlangıçta, bunların nasıl yapıldığına dair hiçbir fikrim yoktu. Daha sonra okudum ve çok şey öğrendim Ana Tudor'un bu güzel öğreticisi.
Görünüşe göre, CSS ile 3B nesneler oluşturmak ve canlandırmak, CSS ile yapmaktan çok farklı değil. karıştırıcı, sadece biraz farklı bir lezzetle.
Sonuç
Bu yazıda CSS animasyonlarının davranışını inceledik. animate-*
mülkiyet değiştirilir. Özellikle “animasyonu tekrar oynatma” ve “yavaş animasyon animasyonu” için çözümler geliştirdik.
Umarım bu makaleyi ilginç bulursunuz. Lütfen düşüncelerinizi bildirin!