Houdini'nin Animasyon İş Akışı

Web uygulamanızın animasyonlarına güç katın

TL;DR: Animasyon İş Akışı, çalışan gereklilik animasyonları yazmanıza olanak tanır. cihazın kendi kare hızında değiştirebilirsiniz. animasyonlarınızı ana iş parçacığı olumsuzluklarına karşı daha dirençli hale getirin ve bağlanabilir kaydırmak için de kullanılır. Animasyon İş Akışı, Chrome Canary'dedir (programın "Deneysel Web Platformu özellikleri" flag) Ayrıca Chrome 71 için bir Kaynak Denemesi planlıyoruz. Bu şablonu aşağıdaki gibi kullanmaya başlayabilirsiniz: bugün daha iyi bir gelecekdir.

Başka bir Animasyon API'si mi var?

Aslına bakarsanız hayır, bu, elimizdeki bilgilerin devamı ve bunun geçerli bir nedeni de var. Baştan başlayalım. Web'de herhangi bir DOM öğesine animasyon eklemek istiyorsanız bugün 2 1⁄2 seçeneğiniz var: CSS Geçişleri basit A'dan B'ye geçişleri, CSS Animasyonlarını döngüsel olabilecek, daha karmaşık, zamana dayalı animasyonlar ve Web Animations API (WAAPI) oluşturabilirsiniz. WAAPI'nin destek matrisi oldukça berbat görünüyor ancak yükseliyor. O zamana kadar polyfill aracılığıyla çalışmaz.

Tüm bu yöntemlerin ortak noktası, bunların durum bilgisiz zaman odaklı olma. Ancak geliştiricilerin denediği bazı efektler ne zaman bağlı ne de durum bilgisizdi. Örneğin, kötü şöhretli paralaks kaydırıcısı kaydırmaya dayalı olduğu anlamına gelir. Günümüzde web'de yüksek performanslı bir paralaks kaydırıcıyı uygulamak şaşırtıcı derecede zordur.

Peki, durum bilgisizliğe ne olacak? Chrome'un Android'deki adres çubuğunu düşünün örneğine bakalım. Ekranı aşağı kaydırırsanız görünüm dışına çıkar. Ancak yukarı kaydırdığınızda, yolun yarısında olsanız bile geri gelir bir düğme gibi görünür. Animasyon yalnızca kaydırma konumuna değil, aynı zamanda kaydırma yönünüz görüntülenir. Durum bilgilidir.

Diğer bir sorun da kaydırma çubuklarının stilini ayarlamayla ilgilidir. Esnektir ve esnektir. yeterince stilize edilmemesi gerekir. Kaydırma çubuğum olarak nyan kedi kullanmak istersem ne olur? Hangi tekniği seçerseniz seçin, özel bir kaydırma çubuğu oluşturmak yüksek performanslı, kolay.

Tüm bunların tuhaf olması ve bunların imkansız etkili şekilde uygulayabilirsiniz. Bu ihtiyaçların çoğu etkinliklere ve/veya requestAnimationFrame, ekranınız kapalıyken bile 60 fps'de ilerlemenizi sağlayabilir. 90 fps, 120 fps veya daha yüksek hızlarda çalışabilir ve ana iş parçacığı çerçevenize bütçe ayırmalıdır.

Animasyon İş Akışı, web'in animasyon yığınının özelliklerini genişleterek kolaylaştırır. Başlamadan önce, iyi bir proje yöneticisi en son gelişmelerden haberdar olun.

Animasyonlar ve zaman çizelgeleri hakkında bir yardım

WAAPI ve Animation Worklet, size zaman çizelgelerini kapsamlı şekilde animasyonları ve efektleri istediğiniz şekilde düzenleyebilirsiniz. Bu bölüm, kısa bir tazeleme veya zaman çizelgelerine giriş yapma ve bunların animasyonlarla nasıl çalıştığını öğrenme.

Her dokümanda document.timeline var. Doküman şu durumda olduğunda 0'dan başlar: oluşturulur ve dokümanın var olmaya başlamasından bu yana geçen milisaniye sayısı sayılır. Tümü dokümanın animasyonları bu zaman çizelgesine göre çalışır.

Konuyu biraz daha somut hale getirmek için, bu WAAPI snippet'ine bakalım

const animation = new Animation(
  new KeyframeEffect(
    document.querySelector('#a'),
    [
      {
        transform: 'translateX(0)',
      },
      {
        transform: 'translateX(500px)',
      },
      {
        transform: 'translateY(500px)',
      },
    ],
    {
      delay: 3000,
      duration: 2000,
      iterations: 3,
    }
  ),
  document.timeline
);

animation.play();

animation.play() adını verdiğimizde animasyon, zaman çizelgesinin currentTime özelliğini kullanır başlangıç zamanı olarak ayarlayın. Animasyonumuzda 3000 ms gecikme vardır, yani zaman çizelgesi "startTime" değerine ulaştığında animasyon başlar (veya "etkin" hale gelir)

  • 3000. After that time, the animation engine will animate the given element from the first keyframe (translateX(0)), through all intermediate keyframes (translateX(500px)) all the way to the last keyframe (translateY(500px)) in exactly 2000ms, as prescribed by thedurationoptions. Since we have a duration of 2000ms, we will reach the middle keyframe when the timeline'scurrentTimeisstartTime + 3000 + 1000and the last keyframe atstartTime + 3000 + 2000". Önemli olan, Zaman çizelgesi, animasyonumuzdaki yeri kontrol eder.

Animasyon son animasyon karesine ulaştığında ilk animasyon karesine atlar animasyon karesini ekleyin ve animasyonun sonraki yinelemesini başlatın. Bu işlemde, iterations: 3 ayarladığımızdan beri toplam 3 kez. Animasyonun genel olarak asla durmayın, iterations: Number.POSITIVE_INFINITY yazarız. İşte kodun sonucu bölümünü ziyaret edin.

WAAPI inanılmaz derecede güçlüdür ve bu API'de sayısını, başlangıçtaki ofsetleri, animasyon karesi ağırlıklarını ve dolgu davranışını bu makalenin kapsamında yer alır. Daha fazla bilgi edinmek istiyorsanız CSS Püf Noktalarında CSS Animasyonları ile ilgili bu makaleyi okumanızı öneririz.

Animasyon İş Akışı Yazma

Artık zaman çizelgesi kavramını kavradığımıza göre Animasyon İş Akışı ve zaman çizelgeleriyle kurcalamanıza nasıl olanak tanıdığı Animasyon Worklet API yalnızca WAAPI'ye dayalı değildir, aynı zamanda genişletilebilir web anlamında çalışan daha düşük düzeyli bir temel öğedir. WAAPI'nin nasıl çalıştığı açıklanmaktadır. Söz dizimi açısından son derece benzerler:

Animasyon İş Akışı WAAPI (WAAPI)
new WorkletAnimation(
  'passthrough',
  new KeyframeEffect(
    document.querySelector('#a'),
    [
      {
        transform: 'translateX(0)'
      },
      {
        transform: 'translateX(500px)'
      }
    ],
    {
      duration: 2000,
      iterations: Number.POSITIVE_INFINITY
    }
  ),
  document.timeline
).play();
      
        new Animation(

        new KeyframeEffect(
        document.querySelector('#a'),
        [
        {
        transform: 'translateX(0)'
        },
        {
        transform: 'translateX(500px)'
        }
        ],
        {
        duration: 2000,
        iterations: Number.POSITIVE_INFINITY
        }
        ),
        document.timeline
        ).play();
        

Aradaki fark, worklet adlı iş akışının adı olan ilk parametrededir. devreye girer.

Özellik algılama

Chrome, bu özelliği gönderen ilk tarayıcı olduğundan kodu, AnimationWorklet öğesinin olmasını beklemiyor. Bu nedenle, çalışmasının desteklenip desteklenmediğini belirlememiz Basit bir onayla AnimationWorklet:

if ('animationWorklet' in CSS) {
  // AnimationWorklet is supported!
}

İş akışı yükleniyor

İş akışları, Houdini görev gücü tarafından, yürütülen birçok iş daha kolay oluşturulur ve ölçeklendirilir. Daha sonra iş akışlarının ayrıntılarına değineceğiz. ancak basitlik açısından bunları ucuz ve hafif ileti dizileri (ör. çalışanlar) kullanabilirsiniz.

"Posta geçiş" adlı bir iş akışı yüklediğimizden emin olmamız gerekir. animasyonu bildirmeden önce:

// index.html
await CSS.animationWorklet.addModule('passthrough-aw.js');
// ... WorkletAnimation initialization from above ...

// passthrough-aw.js
registerAnimator(
  'passthrough',
  class {
    animate(currentTime, effect) {
      effect.localTime = currentTime;
    }
  }
);

Burada ne oluyor? Animatör olarak bir sınıfı kaydetmek üzere AnimationWorklet'ın registerAnimator() çağrısıyla "passthrough" (geçiş) adını almıştır. Bu, yukarıdaki WorkletAnimation() oluşturucuda kullandığımız addır. Bir tamamlandığına göre, addModule() tarafından verilen sözü iptal edip bu iş akışını kullanarak animasyonlar oluşturmaya başlayabiliriz.

Örneğinizin animate() yöntemi, tablodaki her çerçeve için tarayıcı, animasyon zaman çizelgesinin currentTime değerini ileterek oluşturmak istiyor yanı sıra o anda işlenen etkiye göre hareket eder. Sadece bir tane var KeyframeEffect efekt için currentTime localTime bu yüzden bu animatöre "geçiş reklamı" deniyor. Şunun için bu kodla: yukarıdaki iş akışı, WAAPI ve AnimationWorklet tam olarak gösterildiği gibi, demo.

Saat

animate() yöntemimizin currentTime parametresi,currentTime WorkletAnimation() oluşturucusuna ilettiğimiz zaman çizelgesi. Önceki örneği üzerinden geçtik. Ama bu müşteri için JavaScript kodu kullanarak zamanı bozabiliriz 💫

function remap(minIn, maxIn, minOut, maxOut, v) {
  return ((v - minIn) / (maxIn - minIn)) * (maxOut - minOut) + minOut;
}
registerAnimator(
  'sin',
  class {
    animate(currentTime, effect) {
      effect.localTime = remap(
        -1,
        1,
        0,
        2000,
        Math.sin((currentTime * 2 * Math.PI) / 2000)
      );
    }
  }
);
.

currentTime olan Math.sin() değerini alıyoruz ve bu değeri [0; 2000], yani efektimizin tanımlandığı zaman aralığıdır. Şimdi animasyon çok farklı görünüyor. animasyon karelerini veya animasyon seçeneklerini değiştirdik. İş akışı kodu, karmaşıktır ve hangi efektlerin etkili olduğunu programlı bir şekilde tanımlamanıza hangi sırada ve ne ölçüde oynandığını gösterir.

Seçenekler Üzerinden Seçenekler

Bir iş anahtarını yeniden kullanmak ve sayısını değiştirmek isteyebilirsiniz. Bu nedenle WorkletAnimation oluşturucusu, çalışma alanına bir seçenek nesnesini iletmenizi sağlar:

registerAnimator(
  'factor',
  class {
    constructor(options = {}) {
      this.factor = options.factor || 1;
    }
    animate(currentTime, effect) {
      effect.localTime = currentTime * this.factor;
    }
  }
);

new WorkletAnimation(
  'factor',
  new KeyframeEffect(
    document.querySelector('#b'),
    [
      /* ... same keyframes as before ... */
    ],
    {
      duration: 2000,
      iterations: Number.POSITIVE_INFINITY,
    }
  ),
  document.timeline,
  {factor: 0.5}
).play();
.

Bu örnekte, her iki animasyon da aynı kodla, ancak farklı seçeneklerle çalıştırılır.

Bulunduğunuz eyaleti belirtin.

Daha önce de belirttiğim gibi, animasyon iş akışının çözmeyi hedeflediği temel sorunlardan biri, durum bilgili animasyonlar. Animasyon işletlerinin durum kullanmasına izin veriliyor. Ancak bir özelliklerinden biri, iş akışlarının farklı bir veya onları imha etmeye devam eder. Aksi halde, durumu. Durum kaybını önlemek için animasyon iş akışı, bir iş ortağı yok edilmeden önce çağrılır ve durumu döndürmek için kullanabilirsiniz. nesnesini tanımlayın. Bu nesne, çalışma alanı yeniden oluşturulması gerekir. İlk oluşturma sırasında bu parametre undefined olacaktır.

registerAnimator(
  'randomspin',
  class {
    constructor(options = {}, state = {}) {
      this.direction = state.direction || (Math.random() > 0.5 ? 1 : -1);
    }
    animate(currentTime, effect) {
      // Some math to make sure that `localTime` is always > 0.
      effect.localTime = 2000 + this.direction * (currentTime % 2000);
    }
    destroy() {
      return {
        direction: this.direction,
      };
    }
  }
);

Bu demoyu her yenilediğinizde karenin dönme şansı. Tarayıcı bozulacaksa iş parçasını farklı bir iş parçacığına taşırsanız, Math.random() oluşturma çağrısı. Bu durum, girin. Bunun gerçekleşmediğinden emin olmak için animasyonları rastgele seçilen yönü durum olarak ayarlayın ve sağlanmışsa oluşturucuda kullanın.

Uzay-zaman döngüsüyle ilgili ayrıntılar: ScrollTimeline

Önceki bölümde gösterildiği gibi, AnimationWorklet zaman çizelgesinde ilerlemenin zaman çizelgesi üzerindeki etkilerini animasyon ekler. Şimdiye kadar zaman çizelgemiz document.timeline oldu. takip eder.

ScrollTimeline, yeni olanaklar sunar ve animasyonları yönlendirmenizi sağlar. kaydırmayla başlayacağız. İlk e-postalarımızı yeniden kullanacağız. "posta geçiş" bunun için iş akışı demo:

new WorkletAnimation(
  'passthrough',
  new KeyframeEffect(
    document.querySelector('#a'),
    [
      {
        transform: 'translateX(0)',
      },
      {
        transform: 'translateX(500px)',
      },
    ],
    {
      duration: 2000,
      fill: 'both',
    }
  ),
  new ScrollTimeline({
    scrollSource: document.querySelector('main'),
    orientation: 'vertical', // "horizontal" or "vertical".
    timeRange: 2000,
  })
).play();

document.timeline öğesini iletmek yerine yeni bir ScrollTimeline oluşturuyoruz. Tahmin edebileceğiniz gibi, ScrollTimeline zaman harcamaz ancak Çalışma alanındaki currentTime öğesini ayarlamak için scrollSource ürününün kaydırma konumu. Olmak en üste (veya sola) kaydırması currentTime = 0 anlamına gelirken, en alta (veya sağa) kaydırıldığında currentTime, timeRange. Bu demo oynayabilirsiniz. kırmızı kutunun konumunu kontrol edebilirsiniz.

Kaydırmayan bir öğeye sahip bir ScrollTimeline oluşturursanız zaman çizelgesinin currentTime tarihi NaN olacak. Özellikle de mobil uygulamada currentTime olarak NaN için her zaman hazırlıklı olmalısınız. Genellikle varsayılan olarak 0 değerine ayarlamak mantıklıdır.

Animasyonları kaydırma konumuyla bağlamak uzun zamandır aranan bir özellik. Ancak hiçbir zaman bu düzeyde bir doğruluk seviyesine ulaşılamamıştır (hacky, (CSS3D ile ilgili geçici çözümleri) inceleyin. Animasyon İş Akışı, bu efektlerin basit bir şekilde uygulanmasına dikkat edin. Örnek: bunun gibi paralaks kaydırma efekti demo bunu gösteriyor artık kaydırmaya dayalı bir animasyonu tanımlamak için sadece birkaç satır yeterli.

Gelişmiş seçenekler

İş akışları

İş akışları, yalıtılmış bir kapsamı ve çok küçük bir API'si olan JavaScript bağlamlarıdır. teşekkür ederiz. Küçük API yüzeyi, en baştan itibaren daha agresif bir optimizasyon özellikle de düşük özellikli cihazlarda kullanın. Ayrıca, iş akışları ancak gerektiğinde ileti dizileri arasında taşınabilir. Bu çok önemlidir.

Birleştirici NSync

Bazı CSS özelliklerinin animasyonunun hızlı olduğunu, bazılarının ise değil. Bazı özelliklerin animasyon için GPU'da biraz işlem yapması gerekirken bazıları tüm dokümanı yeniden düzenlemeye zorlayabilir.

Chrome'da (diğer pek çok tarayıcıda olduğu gibi) birleştirici adı verilen bir işlem vardır, Ben burada da yaptığım işi çok basitleştiriyorum. Katmanları, görevleri dokunun ve ardından ekranı mümkün olduğunca düzenli şekilde güncellemek için GPU'yu kullanın. ekranın güncellendiği kadar hızlı (genellikle 60 Hz) olmalıdır. Bu içeriğin hangi CSS özellikleri canlandırılıyor. Tarayıcının oluşturucu işini yaparken, diğer özelliklerin yalnızca ana iş parçacığının yapabileceği işlemdir. Bu mülklerde animasyon iş akışınız ana ekrana bağlı olacaktır. veya birleştiriciyle senkronize olarak ayrı bir iş parçacığında çalıştırmanız gerekir.

Bileğe tokat

Genellikle, kullanıcılar arasında paylaşılan potansiyel olarak yalnızca bir birleştirici işlemi vardır Çünkü GPU yoğun yoğun ilgi gören bir kaynaktır. Birleştirici bir şekilde engellendiğinde, tüm tarayıcı durur ve kullanıcı girişi. Ne pahasına olursa olsun bu durumdan kaçınılmalıdır. Peki kullanıcınız sizin için iş akışı, çerçevenin tamamlanması için birleştiricinin ihtiyaç duyduğu verileri zamanında oluşturulmalı mı?

Bu durumda, özellik uyarınca iş akışının "kaymasına" izin verilir. Planın gerisinde birleştiricinin son karenin verilerini tekrar kullanmasına kare hızını yüksek tutun. Görsel olarak bu iğrenç bir şey gibi görünse de aradaki fark, tarayıcının kullanıcı girişine hâlâ yanıt vermesidir.

Sonuç

AnimationWorklet'ın birçok yönü ve web'e sağladığı faydalar var. Bariz avantajlar, animasyonlar üzerinde daha fazla kontrol sahibi olmak ve animasyonları kullanarak web'e yeni bir görsel kalite düzeyi kazandırdı. Ancak API'ler Ayrıca tasarımdan en iyi şekilde yararlanırken uygulamanızı olumsuzluklara karşı tüm yeni avantajlara aynı anda erişebilecektir.

Animasyon İş Akışı, Canary'de, biz de yeni bir başlangıç noktası oluşturmayı hedefliyoruz. Chrome 71. Yeni web deneyimlerinizi merakla bekliyoruz. konusunda uzlaşın. Ayrıca bir de çoklu dolgu özelliğini kullanmanızı öneririz.

CSS Geçişleri ve CSS Animasyonlarının hâlâ geçerli olduğunu unutmayın. temel animasyonlarda çok daha basit olabilir. Ama daha sonra güzel, AnimationWorklet sizi bekliyor!