Bulanıklaştırma animasyonu

Bulanıklaştırma, kullanıcının dikkatini başka yere yönlendirmek için harika bir yöntemdir. Bazı görsel öğelerin bulanık görünmesini sağlarken diğer öğelerin odakta tutulması doğal olarak kullanıcının odağını yönlendirir. Kullanıcılar bulanıklaştırılan içeriği görmezden gelip okuyabilecekleri içeriğe odaklanır. Bunun bir örneği, fareyle üzerine gelindiğinde tek tek öğelerle ilgili ayrıntıları gösteren bir simge listesidir. Bu süre zarfında, kullanıcıyı yeni görüntülenen bilgilere yönlendirmek için geri kalan seçenekler bulanıklaştırılabilir.

Özet

Bulanıklaştırma çok yavaş bir hareket olduğundan, böyle bir seçenek yoktur. Bunun yerine, gittikçe bulanıklaştırılan bir dizi versiyonu önceden hesaplayın ve bu sürümler arasında geçiş yapın. İş arkadaşım Yi Gu sizin için her şeyi halletmesi için bir kitaplık yazdı. Demomuza göz atın.

Ancak bu teknik, herhangi bir geçiş dönemi olmadan uygulandığında oldukça rahatsız edici olabilir. Bulanıklaştırma efektiyle (bulanıklaştırmanın bulanıklaştırılmadığından bulanıklaştırılmış hâline geçiş) makul bir tercih gibi görünebilir ancak bunu web'de yapmayı denediyseniz büyük olasılıkla animasyonların yumuşak olmadığını fark etmişsinizdir. Bu demo, güçlü bir makineniz olmasa da gösterilmektedir. Daha iyisini yapabilir miyiz?

Sorun

İşaretleme, CPU tarafından dokulara dönüştürülür. Dokular GPU'ya yüklenir. GPU, gölgelendiricileri kullanarak bu dokuları çerçeve arabelleğine çizer. Bulanıklaştırma gölgelendiricide
gerçekleştirilir.

Şu anda bulanıklık animasyonunun verimli bir şekilde çalışmasını sağlayamıyoruz. Bununla birlikte, yeterince iyi görünen, ancak teknik olarak animasyonlu bulanıklık içermeyen bir geçici çözüm bulabiliriz. Başlamak için önce animasyonlu bulanıklığın neden yavaş olduğunu görelim. Web'deki öğeleri bulanıklaştırmak için iki teknik vardır: CSS filter özelliği ve SVG filtreleri. Artan destek ve kullanım kolaylığı sayesinde genellikle CSS filtreleri kullanılır. Maalesef, Internet Explorer'ı desteklemeniz gerekiyorsa SVG filtrelerini IE 10 ve 11 bu filtreleri destekler, ancak CSS filtrelerini desteklemediği için kullanmaktan başka seçeneğiniz yoktur. Neyse ki bulanıklaştırma animasyonu için uyguladığımız geçici çözüm her iki teknikte de işe yarıyor. DevTools'a bakarak bu darboğazı bulmaya çalışalım.

Geliştirici Araçları'nda "Yanıp sönen boyama"yı etkinleştirirseniz herhangi bir yanıp sönme görmezsiniz. Görünüşe göre yeniden boyama yapılmıyor. "Yeniden boyama", CPU'nun tanıtılan öğenin dokusunu yeniden boyaması anlamına geldiği için bu teknik olarak doğrudur. Bir öğe hem tanıtıldığında hem de bulanıklaştırıldığında, GPU tarafından bir gölgelendirici kullanılarak bulanıklaştırma uygulanır.

Hem SVG filtreleri hem de CSS filtreleri, bulanıklaştırma uygulamak için büyüme filtrelerini kullanır. Bükülme filtreleri oldukça pahalıdır. Her çıkış pikseli için birkaç giriş pikselinin dikkate alınması gerekir. Resim ne kadar büyük veya bulanıklık çapı ne kadar büyük olursa efekt de o kadar maliyetli olur.

Sorun tam da burada. Her karede oldukça pahalı bir GPU işlemi çalıştırıyoruz. Bu işlem, kare bütçemizi 16 ms'ye kadar tüketerek 60 fps'nin çok altında sonuç veriyor.

Tavşan deliğinden aşağı

Peki, bu sürecin sorunsuz şekilde ilerlemesi için ne yapabiliriz? El becerisi kullanabiliriz. Gerçek bulanıklaştırma değerini (bulanıklığın yarıçapı) canlandırmak yerine, bulanıklaştırma değerinin katlanarak arttığı birkaç bulanıklaştırılmış kopyayı önceden hesaplar, ardından opacity kullanarak bunlar arasında çapraz geçiş yaparız.

Çapraz şeffaflaşma, opaklıkta şeffaflaşma ve şeffaflaşma olaylarının bir dizisidir. Örneğin, dört bulanıklık aşamasımız varsa birinci aşamanın şeffaflaşması, ikinci aşamada ise aynı anda yapılması gerekir. İkinci aşama% 100 opaklığa ve birinci aşama %0'a ulaştığında, ikinci aşamanın parlaklığını azaltıp üçüncü aşamada şeffaflaştırırız. Bu işlemden sonra, nihayet üçüncü aşamanın soluklaşmasını, dördüncü ve son versiyonunda soluklaşmasını sağlarız. Bu senaryoda her aşama, istenen toplam sürenin dörtte birini alır. Görsel olarak bu, gerçek bir animasyonlu bulanıklığa çok benziyor.

Deneylerimizde, bulanıklık yarıçapını aşama başına katlanarak artırmak en iyi görsel sonuçları sağladı. Örnek: Dört bulanıklaştırma aşamamız varsa her aşamaya filter: blur(2^n) (aşama 0: 1 piksel, aşama 1: 2 piksel, 2. aşama: 4 piksel ve sahne 3: 8 piksel) uygularız. Bu bulanıklaştırılan kopyaların her birini will-change: transform kullanarak kendi katmanlarına zorla ("tanıtım" denir) kullanırsak bu öğelerin opaklığının aşırı hızlı bir şekilde değiştirilmesi gerekir. Teoride bu yöntem, pahalı bulanıklaştırma işini en baştan yüklememize olanak tanır. Mantığın hatalı olduğu ortaya çıktı. Bu demoyu çalıştırırsanız kare hızının hâlâ 60 fps'nin altında olduğunu ve bulanıklaştırmanın aslında öncekinden daha kötü olduğunu görürsünüz.

GPU'nun uzun süre meşgul olduğu yerleri gösteren Geliştirici Araçları.

DevTools'a hızlı bir bakış, GPU'nun hâlâ son derece meşgul olduğunu ve her kareyi ~90 ms'ye kadar uzattığını gösteriyor. Ama neden? Bulanıklaştırma değerini artık değil, yalnızca opaklığı değiştiriyoruz. Peki ne oluyor? Sorun bir kez daha bulanıklaştırma efektinin yapısındadır: Daha önce açıklandığı gibi, öğe hem tanıtılıyor hem de bulanıklaştırılmışsa efekt GPU tarafından uygulanır. Dolayısıyla, bulanıklaştırma değerini artık animasyon olarak uygulamasak bile, dokudaki bulanıklık yine de düzeltilmemiştir ve GPU tarafından her karenin yeniden bulanıklaştırılması gerekir. Kare hızının eskisinden daha da kötü olmasının nedeni, çoğu zaman bağımsız olarak bulanıklaştırılması gereken iki doku görünür olduğundan, naif uygulamaya kıyasla GPU'nun öncekinden daha fazla işinin olmasıdır.

Bulduğumuz şey pek hoş değil ama animasyonu çarpıcı bir şekilde hızlandırıyor. Bulanıklaştırılacak öğeyi tanıtmayın, bunun yerine üst sarmalayıcıyı tanıtacağız. Bir öğe hem bulanıklaştırılır hem de tanıtılırsa bu efekt GPU tarafından uygulanır. Bu nedenle demomuzu yavaşlattık. Öğe bulanıklaştırılır ancak öne çıkarılmazsa bulanıklaştırma bunun yerine en yakın üst dokuya pikselleştirilir. Örneğimizde bu tanıtılan üst sarmalayıcı öğesidir. Bulanıklaştırılmış resim artık üst öğenin dokusudur ve gelecekteki tüm kareler için yeniden kullanılabilir. Bulanıklaştırılmış öğelere animasyon uygulanmadığını ve önbelleğe almanın gerçekten faydalı olduğunu bildiğimizden bu yöntem işe yarar. Bu tekniğin uygulandığı bir demoyu burada bulabilirsiniz. Moto G4'ün bu yaklaşımla ilgili ne düşündüğünü merak ediyorum. Spoiler uyarısı: Çok iyi olduğunu düşünüyor.

GPU'nun çok fazla boşta kalma süresinin olduğu yerleri gösteren Geliştirici Araçları.

Artık GPU'da oldukça yüksek bir boşluk ve 60 fps'de sorunsuz bir deneyime sahibiz. Başardık!

Prodüksiyon hazırlanıyor

Demomuzda, bir DOM yapısını birden fazla kez çoğaltarak içeriğin kopyalarının farklı güçlerde bulanıklaştırılmasını sağladık. Yazarın CSS stilleri, hatta JavaScript'leri ile istenmeyen bazı yan etkileri olabileceği için bunun üretim ortamında nasıl çalışacağını merak ediyor olabilirsiniz. Haklısın. Gölge DOM'yi girin!

Çoğu kişi Gölge DOM'u, Özel Öğelere "dahili" öğeler eklemenin bir yolu olarak düşünse de bu aynı zamanda bir izolasyon ve performans temel öğesidir. JavaScript ve CSS, Gölge DOM sınırlarını geçemez. Bu da, geliştiricinin stillerine veya uygulama mantığına müdahale etmeden içerik çoğaltmamıza olanak tanır. Her kopyanın pikselleştirileceği bir <div> öğemiz var ve artık bu <div> öğelerini gölge ana makine olarak kullanıyoruz. attachShadow({mode: 'closed'}) kullanarak bir ShadowRoot oluşturur ve <div> öğesinin kendisi yerine içeriğin bir kopyasını ShadowRoot öğesine ekleriz. Kopyalarımızın stilinin orijinaliyle aynı olmasını sağlamak için tüm stil sayfalarını da ShadowRoot içine kopyalamamız gerekir.

Bazı tarayıcılar Gölge DOM v1'i desteklemez. Bu durumda, biz yalnızca içeriği çoğaltmaya başlar ve hiçbir şeyin bozulmamasına dikkat ederiz. ShadyCSS ile Gölge DOM çoklu dolgusunu kullanabilirdik ancak bunu kitaplığımızda uygulamadık.

İşte bu kadar. Chrome'un oluşturma ardışık düzenine doğru ilerledikten sonra, bulanıklaştırmaları tarayıcılarda etkili bir şekilde canlandırabileceğimizi keşfettik.

Sonuç

Bu tür efektler kolayca kullanılmamalıdır. DOM öğelerini kopyalayıp kendi katmanlarına zorlamamız nedeniyle, alt uç cihazların sınırlarını zorlayabiliriz. Her bir ShadowRoot için tüm stil sayfalarını kopyalamak da potansiyel bir performans riski teşkil eder. Bu nedenle, mantığınızı ve stillerinizi LightDOM içindeki kopyalardan etkilenmeyecek şekilde ayarlamayı mı, yoksa ShadowDOM tekniğimizi kullanmayı mı tercih edeceğinize karar vermelisiniz. Ancak bazen tekniğimiz, değerli bir yatırım olabilir. GitHub depomuzdaki koda ve demoya göz atın. Sorularınız olursa Twitter'dan benimle iletişime geçebilirsiniz.