Yükleme ekranındaki takılmayı compositor'a taşımak
DEVILYXRD yazan açılış ekranı ilk sürümde takılıyordu. Çözüm daha hızlı JavaScript yazmak değil, ana iş parçacığına hiç iş bırakmamaktı: dört gerçek kilometre taşı, yalnızca transform ile hareket eden parçalar ve işler ters gittiğinde devreye giren zamanlayıcılar.
01Neden takılıyordu
Açılış ekranı, tarayıcının en meşgul olduğu anda çalışıyor: HTML ayrıştırılıyor, fontlar iniyor, JavaScript paketi çözülüyor ve Vue prerender edilmiş sayfanın üzerine hidrasyon yapıyor. İlk sürümde ilerleme çubuğu ve sayaç, yaklaşık 16 milisaniyede bir çalışan bir JavaScript döngüsüyle güncelleniyordu. Ana iş parçacığı uygulamayı kurarken bu döngünün adımları gecikiyor, animasyon tam da ekranda göründüğü anda kesik kesik ilerliyordu.
Ekranın kendisi index.html içinde, satır içi CSS ve satır içi bir script olarak duruyor. Böylece hiçbir JavaScript paketi ya da font gelmeden boyanabiliyor. Kapsayıcıda contain: strict var; içindeki hiçbir değişiklik sayfanın geri kalanının düzenini etkilemiyor.
02Sadece transform
Kuralı basit tuttum: açılış ekranında hareket eden her şey yalnızca transform kullanacak, solarken de opacity. Bu iki özellik tarayıcının compositor katmanında canlandırılabiliyor; ana iş parçacığı meşgulken bile akıcı kalıyorlar. JavaScript artık animasyonu yürütmüyor, yalnızca hedef değeri yazıyor. Aradaki hareketi bir CSS geçişi yapıyor.
Perde .out sınıfı eklendiğinde translateY(-100%) ile yukarı kayıyor. DEVILYXRD harflerinin her biri ayrı bir span; başta translateY(112%) ile aşağıda saklı duruyorlar ve .ready sınıfı geldiğinde yerlerine çıkıyorlar. Her harfin --i değişkeni geçiş gecikmesini 55 milisaniyelik adımlarla kaydırıyor, kelime soldan sağa açılıyor. Çıkışta aynı harfler -112% ile yukarı kaçıyor, bu kez 22 milisaniyelik adımlarla. Çubuk genişliğini değil scaleX değerini değiştiriyor.
function set(v) {
if (v <= shown) return
shown = v
bar.style.transform = 'scaleX(' + v / 100 + ')'
var d = [Math.floor(v / 100), Math.floor(v / 10) % 10, v % 10]
for (var i = 0; i < 3; i++)
cols[i].style.transform = 'translateY(' + (-1.6 * d[i]) + 'em)'
}Sayaç bir odometre. Her basamak, alt alta dizilmiş rakamlardan oluşan bir şerit: yüzler basamağında yalnızca 0 ve 1, onlar ve birler basamağında 0'dan 9'a kadar. Her rakam 1.6em yüksekliğinde ve basamağın penceresi de 1.6em. Doğru rakamı göstermek için şeridi -1.6 × rakam kadar yukarı kaydırmak yetiyor; geçişi yine CSS yapıyor. set fonksiyonu daha küçük bir değeri yok sayıyor, yani sayaç hiçbir zaman geri gitmiyor.
03Dört gerçek kilometre taşı
Sahte bir zamanlayıcı yerine ilerleme gerçek olaylara bağlı. Script çalıştıktan bir görev sonra değer 12 oluyor; bunu bir setTimeout ile geciktirmemin sebebi ilk geçişin gerçekten canlanması. DOMContentLoaded geldiğinde 42. document.fonts.load ile Syne 800 ve IBM Plex Mono 500 yüklendiğinde 76 oluyor ve harflerin açılmasını başlatan .ready sınıfı ekleniyor. Son adım 100: main.ts uygulamayı mount ettikten sonra boot.ts içindeki bootDone fonksiyonunu çağırıyor, o da document.fonts.ready'yi bekleyip window.__bootDone'u tetikliyor.
Her kilometre taşının bir de güvenlik ağı var. Font bekleme en fazla 1,5 saniye sürüyor; o süre dolunca harfler fontu beklemeden açılıyor. Uygulama hiç haber vermezse 6 saniye sonunda __bootDone yine de çağrılıyor. Ekran en az yaklaşık 1,1 saniye kalıyor ki harfler hareketini bitirsin. 100'e ulaştıktan sonra da 420 milisaniye bekleniyor; çubuk yerine otursun ve hidrasyonu biten sayfa perdenin altında bir kez boyansın.
04Perde kalkarken
leave fonksiyonu .out sınıfını ekliyor, window.__bootLeft değerini true yapıyor ve boot:leave adında bir olay yayınlıyor. Eleman, geçiş bittikten sonra DOM'dan siliniyor ve <html> üzerindeki, kaydırmayı kilitleyen booting sınıfı kaldırılıyor. boot.ts içindeki bootReady sözü bu olayı bekliyor; sunucuda, açılış ekranı olmayan bir sayfada ya da perde zaten kalkmışsa hemen çözülüyor. Ana sayfadaki HeroScene animasyonunu bootReady.then ile başlatıyor; böylece hero, perdenin arkasında değil, perde kalkarken açılıyor.
Script iki noktada performance.mark çağırıyor: fontlar hazır olduğunda boot:fonts, perde kalkarken boot:leave. Bu işaretler tarayıcının performans panelinde zaman çizelgesinin üzerinde görünüyor ve açılışın hangi adımda beklediğini tahmin etmek yerine görmeyi sağlıyor.
05Hareket istemeyenler için
İşletim sisteminde hareketi azaltma tercihi açıksa ekran farklı davranıyor. prefers-reduced-motion altında harfler, çubuk ve sayaç geçişsiz, doğrudan son hallerinde duruyor. Perde kaymak yerine 240 milisaniyede soluyor. En kısa süre 1,1 saniyeden 200 milisaniyeye iniyor, 100'den sonraki bekleme kalkıyor ve eleman 300 milisaniye sonra siliniyor. Aynı kontrol hem CSS'te media query olarak hem de script'te matchMedia ile yapılıyor; zamanlamalar da tercihe uyuyor.
Akıcılık çoğu zaman kodu hızlandırmakla değil, işi ana iş parçacığından çıkarmakla gelir.
Bu değişiklikten sonra script'in yaptığı iş birkaç satır stil yazmaktan ibaret. Ana iş parçacığı ne kadar meşgul olursa olsun, bir sonraki hedef değer geldiğinde hareket kaldığı yerden devam ediyor.