Bulanıklaştırma, kullanıcının dikkatini başka bir noktaya yönlendirmek için harika bir yöntemdir. Bazı görsel öğeleri bulanıklaştırıp diğer öğeleri odaklanmış şekilde tutmak, kullanıcının dikkatini doğal olarak yönlendirir. Kullanıcılar bulanıklaştırılmış içeriği görmezden gelip okuyabildikleri içeriğe odaklanıyor. Örneğin, üzerine gelindiğinde öğelerle ilgili ayrıntıları gösteren bir simge listesi. Bu süre zarfında, kullanıcının yeni görüntülenen bilgilere yönlendirilmesi için kalan seçenekler bulanıklaştırılabilir.
Özet
Bulanıklık animasyonu çok yavaş olduğundan pek tercih edilmez. Bunun yerine, giderek daha fazla bulanıklaştırılmış bir dizi sürümü önceden hesaplayın ve bunlar arasında çapraz geçiş yapın. Meslektaşım Yi Gu, her şeyi sizin için halledecek bir kitaplık yazdı. Demomuza göz atın.
Ancak bu teknik, geçiş dönemi olmadan uygulandığında oldukça rahatsız edici olabilir. Bulanıklaştırmayı animasyonla göstermek (bulanık olmayan bir görüntüden bulanık bir görüntüye geçiş) mantıklı bir seçim gibi görünse de bunu web'de yapmayı denediyseniz güçlü bir makineniz yoksa animasyonların hiç de sorunsuz olmadığını fark etmişsinizdir. Bu demo, bu durumu gösteriyor. Daha iyi hizmet verebilir miyiz?
Sorun

Şu an için bulanıklık animasyonunu verimli bir şekilde çalıştıramıyoruz. Ancak yeterince iyi görünen ancak teknik olarak animasyonlu bulanıklık olmayan bir geçici çözüm bulabiliriz. Başlamak için öncelikle animasyonlu bulanıklaştırmanın neden yavaş olduğunu anlayalım. Web'deki öğeleri bulanıklaştırmak için iki teknik vardır: CSS filter
özelliği ve SVG filtreleri. CSS filtreleri, destek ve kullanım kolaylığı sayesinde genellikle kullanılır. Maalesef Internet Explorer'ı desteklemeniz gerekiyorsa SVG filtrelerini kullanmaktan başka seçeneğiniz yoktur. Çünkü IE 10 ve 11, CSS filtrelerini değil SVG filtrelerini destekler. İyi haber şu ki, bulanıklık animasyonu için geçici çözümümüz her iki teknikle de çalışıyor. Bu nedenle, Geliştirici Araçları'na bakarak darboğazı bulmaya çalışalım.
Geliştirici Araçları'nda "Boyama Yanıp Sönmesi"ni etkinleştirirseniz herhangi bir yanıp sönme görmezsiniz. Yeniden boyama işlemi yapılmıyor. "Yeniden çizme", CPU'nun tanıtılan bir öğenin dokusunu yeniden çizmesi anlamına geldiğinden bu ifade teknik olarak doğrudur. Bir öğe hem tanıtıldığında hem de bulanıklaştırıldığında bulanıklık, gölgelendirici kullanılarak GPU tarafından uygulanır.
Hem SVG filtreleri hem de CSS filtreleri, bulanıklık uygulamak için konvolüsyon filtrelerini kullanır. Evrişim filtreleri, her çıkış pikseli için bir dizi giriş pikselinin dikkate alınması gerektiğinden oldukça maliyetlidir. Görüntü ne kadar büyükse veya bulanıklık yarıçapı ne kadar büyükse efekt o kadar maliyetli olur.
Sorun da burada. Her karede oldukça maliyetli bir GPU işlemi çalıştırıyoruz. Bu da 16 ms olan kare bütçemizi aşıyor ve sonuç olarak 60 FPS'nin çok altında kalıyoruz.
Kaosun içine ilerliyorsunuz
Peki bu süreci sorunsuz hale getirmek için ne yapabiliriz? El çabukluğunu kullanabiliriz. Gerçek bulanıklık değerini (bulanıklığın yarıçapı) animasyonla göstermek yerine, bulanıklık değerinin katlanarak arttığı birkaç bulanık kopya önceden hesaplanır ve opacity
kullanılarak bunlar arasında çapraz geçiş yapılır.
Çapraz geçiş, üst üste binen opaklıkta açılma ve opaklıkta kapanma serisidir. Örneğin, dört bulanıklaştırma aşamamız varsa aynı anda ikinci aşamayı belirginleştirirken ilk aşamayı bulanıklaştırırız. İkinci aşama% 100 opaklığa, birinci aşama ise %0 opaklığa ulaştığında üçüncü aşamayı görünür hale getirirken ikinci aşamayı görünmez hale getiririz. Bu işlem tamamlandıktan sonra üçüncü aşamayı tamamen silip dördüncü ve son versiyonu ekliyoruz. Bu senaryoda her aşama, istenen toplam sürenin ¼'ü kadar sürer. Görsel olarak bu, gerçek ve animasyonlu bir bulanıklığa çok benzer.
Denemelerimizde, bulanıklık yarıçapını her aşamada katlanarak artırmanın en iyi görsel sonuçları verdiğini gördük. Örnek: Dört bulanıklaştırma aşaması varsa her aşamaya filter: blur(2^n)
uygularız. Örneğin, 0. aşama: 1 piksel, 1. aşama: 2 piksel, 2. aşama: 4 piksel ve 3. aşama: 8 piksel. will-change: transform
kullanarak bu bulanıklaştırılmış kopyaların her birini kendi katmanına ("tanıtım" olarak adlandırılır) zorlarsak bu öğelerin opaklığını değiştirmek çok hızlı olmalıdır. Teoride bu, bulanıklaştırma işleminin maliyetli kısmını önceden yapmamıza olanak tanır. Ancak bu mantığın hatalı olduğu ortaya çıktı. Bu demoyu çalıştırırsanız kare hızının hâlâ 60 kare/sn'nin altında olduğunu ve bulanıklığın eskisinden daha kötü olduğunu görürsünüz.

DevTools'a hızlıca göz attığımızda GPU'nun hâlâ çok meşgul olduğunu ve her kareyi yaklaşık 90 ms'ye uzattığını görüyoruz. Peki neden? We are not changing the blur value anymore, only the opacity, so what's happening? Sorun yine bulanıklaştırma efektinin doğasından kaynaklanıyor: Daha önce açıklandığı gibi, öğe hem tanıtılıyor hem de bulanıklaştırılıyorsa efekt GPU tarafından uygulanır. Bu nedenle, bulanıklık değerini artık animasyonla göstermiyor olsak da doku bulanık değildir ve her karede GPU tarafından yeniden bulanıklaştırılması gerekir. Kare hızının eskisinden daha da kötü olmasının nedeni, basit uygulamaya kıyasla GPU'nun aslında daha fazla iş yapmasıdır. Çünkü çoğu zaman iki doku görünür ve bunların bağımsız olarak bulanıklaştırılması gerekir.
Ortaya çıkan sonuç pek güzel olmasa da animasyonu inanılmaz derecede hızlı hale getiriyor. Bulanıklaştırılacak öğenin tanıtımını yapmamaya geri döneriz ancak bunun yerine bir üst sarmalayıcıyı tanıtırız. Bir öğe hem bulanıklaştırılmış hem de öne çıkarılmışsa efekt, GPU tarafından uygulanır. Bu durum, demomuzun yavaşlamasına neden oldu. Öğe bulanıklaştırılmış ancak tanıtılmamışsa bulanıklık bunun yerine en yakın üst dokuya rasterleştirilir. Bu örnekte, tanıtılan üst sarmalayıcı öğe kullanılmıştır. Bulanıklaştırılmış resim artık üst öğenin dokusudur ve gelecekteki tüm çerçeveler için yeniden kullanılabilir. Bu yalnızca bulanıklaştırılmış öğelerin animasyonlu olmadığını ve bunları önbelleğe almanın aslında faydalı olduğunu bildiğimiz için çalışır. Bu tekniğin uygulandığı bir demoyu burada bulabilirsiniz. Moto G4'ün bu yaklaşımla ilgili ne düşündüğünü merak ediyorum. Spoiler uyarısı: Harika olduğunu düşünüyor:

Artık GPU'da bolca yerimiz var ve 60 FPS'lik akıcı bir performans elde ediyoruz. Başardık!
Üretime hazırlama
Demomuzda, içeriğin farklı güçlerde bulanıklaştırılacak kopyalarını elde etmek için bir DOM yapısını birden çok kez kopyaladık. Bunun üretim ortamında nasıl çalışacağını merak ediyor olabilirsiniz. Çünkü bu durum, yazarın CSS stillerinde veya JavaScript'inde bazı istenmeyen yan etkilere neden olabilir. Haklısınız. Enter Shadow DOM!
Çoğu kişi Shadow DOM'u "dahili" öğeleri özel öğelerine eklemenin bir yolu olarak düşünse de bu, aynı zamanda bir izolasyon ve performans öğesidir. JavaScript ve CSS, Shadow DOM sınırlarını aşamaz. Bu sayede, geliştiricinin stillerine veya uygulama mantığına müdahale etmeden içeriği kopyalayabiliriz. Her kopyanın üzerine rasterleştirileceği bir <div>
öğemiz zaten var ve artık bu <div>
öğelerini gölge ana makineleri olarak kullanıyoruz. attachShadow({mode: 'closed'})
kullanarak ShadowRoot
oluştururuz ve içeriğin bir kopyasını <div>
yerine ShadowRoot
'ya ekleriz. Kopyalarımızın orijinalle aynı şekilde biçimlendirilmesini sağlamak için tüm stil sayfalarını da ShadowRoot
'ya kopyalamamız gerekir.
Bazı tarayıcılar Shadow DOM v1'i desteklemez. Bu tarayıcılarda, içeriği yalnızca kopyalayıp hiçbir şeyin bozulmaması için en iyisini umarız. Shadow DOM polyfill'i ShadyCSS ile birlikte kullanabilirdik ancak bunu kitaplığımızda uygulamadık.
İşte bu kadar. Chrome'un oluşturma işlem hattında yaptığımız yolculuktan sonra, bulanıklaştırma efektlerini tarayıcılarda nasıl verimli bir şekilde canlandırabileceğimizi öğrendik.
Sonuç
Bu tür efektler dikkatli kullanılmalıdır. DOM öğelerini kopyalayıp kendi katmanlarına zorladığımız için daha düşük seviyedeki cihazların sınırlarını zorlayabiliriz. Tüm stil sayfalarını her ShadowRoot
öğesine kopyalamak da olası bir performans riski oluşturur. Bu nedenle, mantığınızı ve stillerinizi LightDOM
öğesindeki 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 göz atın. Ayrıca demoyu inceleyin ve sorularınız olursa Twitter'da bize ulaşın.