Bulanıklaştırma, kullanıcının dikkatini başka bir yere yönlendirmenin mükemmel bir yoludur. Bazı görsel öğeleri bulanıklaştırırken diğer öğeleri odakta tutmak, kullanıcının dikkatini doğal bir şekilde yönlendirir. Kullanıcılar bulanık içeriği görmezden gelir ve bunun yerine okuyabilecekleri içeriğe odaklanır. Örneğin, imleci üzerine getirdiğinizde öğelerle ilgili ayrıntıları gösteren simgelerin listesi. Bu süre zarfında, kullanıcıyı yeni görüntülenen bilgilere yönlendirmek için kalan seçenekler bulanıklaştırılabilir.
Özet
Bulanıklaştırmayı animasyonlu hale getirmek çok yavaş olduğu için pek uygun bir seçenek değildir. Bunun yerine, giderek bulanıklaşan bir dizi sürümü önceden hesaplayıp aralarında geçiş yapabilirsiniz. İş arkadaşım Yi Gu, sizin için her şeyi halledecek bir kitaplık yazdı. Demomuza göz atın.
Ancak bu teknik, geçiş dönemi olmadan uygulandığında oldukça can sıkıcı olabilir. Bulanıklaştırma animasyonu (bulanık olmayandan bulanıklığa geçiş) makul bir seçim gibi görünse de bunu web'de denediyseniz animasyonların hiç de akıcı olmadığını fark etmişsinizdir. Güçlü bir makineniz yoksa bu demo da bunu gösteriyor. Daha iyisini yapabilir miyiz?
Sorun
Şu anda bulanıklaştırma animasyonu verimli bir şekilde çalışmıyor. Bununla birlikte, yeterince iyi görünen ancak teknik olarak animasyonlu bir bulanıklık olmayan bir geçici çözüm bulabiliriz. Öncelikle, animasyonlu bulanıklığı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. Daha fazla destek ve kullanım kolaylığı sayesinde genellikle CSS filtreleri kullanılır. Maalesef Internet Explorer'ı desteklemeniz gerekiyorsa IE 10 ve 11 CSS filtrelerini desteklemediğinden SVG filtrelerini kullanmaktan başka seçeneğiniz yoktur. Güzel bir haberimiz var. Bulanıklaştırmayı animasyonlu hale getirmeyle ilgili geçici çözümümüz her iki teknikte de işe yaramaktadır. Geliştirici Araçları'na bakarak darboğazları bulmaya çalışalım.
Geliştirici Araçları'nda "Boya Yanıp Sönme"yi etkinleştirirseniz hiç yanıp sönme görmezsiniz. Yeniden boyama işlemi yapılmamış. "Yeniden boyama", CPU'nun tanıtılan bir öğenin dokusunu yeniden boyaması anlamına geldiğinden bu teknik olarak doğrudur. Bir öğe hem öne çıkarıldığı hem de bulanıklaştırıldığı zaman bulanıklık, GPU tarafından bir gölgelendirici kullanılarak uygulanır.
Hem SVG filtreleri hem de CSS filtreleri, bulanıklık uygulamak için dönüşüm filtreleri kullanır. Her çıkış pikseli için bir dizi giriş pikseli dikkate alınması gerektiğinden, konvolüsyon filtreleri oldukça pahalıdır. Resim veya bulanıklık yarıçapı ne kadar büyükse efekt o kadar maliyetlidir.
Sorun da burada başlıyor. Her karede oldukça pahalı bir GPU işlemi gerçekleştiriyoruz. Bu da 16 ms.lik kare bütçemizi aşıyor ve sonuç olarak 60 fps'nin çok altında bir değere ulaşıyoruz.
Kaosun içine inme
Bu işlemin sorunsuz bir şekilde yapılması için ne yapabiliriz? El çabukluğu kullanabiliriz. Gerçek bulanıklık değerini (bulanıklığın yarıçapı) animasyonlu olarak göstermek yerine, bulanıklık değerinin katlanarak arttığı birkaç bulanık kopyayı önceden hesaplar ve ardından opacity
kullanarak bunlar arasında geçiş yaparız.
Geçiş, bir dizi örtüşen opaklık fade-in ve fade-out'tan oluşur. Örneğin, dört bulanıklık aşamamız varsa ilk aşamayı soluklaştırırken aynı anda ikinci aşamayı belirginleştiririz. İ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ı yavaş yavaş azaltıp dördüncü ve son sürümü yavaş yavaş belirginleştiririz. Bu senaryoda her aşama, istenen toplam sürenin ¼'ünü alır. Görsel olarak bu, gerçek ve hareketli bir bulanıklığa çok benziyor.
Denemelerimizde, bulanıklık yarıçapını aşama başına katlanarak artırmak en iyi görsel sonuçları verdi. Örnek: Dört bulanıklık aşamamız varsa her aşamaya filter: blur(2^n)
uygularız. Yani 0. aşama: 1 piksel, 1. aşama: 2 piksel, 2. aşama: 4 piksel ve 3. aşama: 8 piksel. Bu bulanık kopyaların her birini will-change: transform
kullanarak kendi katmanına zorlarsak ("yükseltme" olarak adlandırılır) bu öğelerin opaklığını değiştirmek çok hızlı olur. Teorik olarak bu, bulanıklaştırmayla ilgili pahalı işi önden yüklememize 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 fps'nin altında olduğunu ve bulanıklığın aslında öncekinden 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? Artık bulanıklık değerini değil, yalnızca opaklığı değiştiriyoruz. Peki ne oluyor? Sorun yine bulanıklık efektinin doğasındadır: Daha önce de açıklandığı gibi, öğe hem öne çıkarılmış hem de bulanıklaştırılmışsa efekt GPU tarafından uygulanır. Bu nedenle, bulanıklık değerini artık animasyonlu olarak göstermesek de dokunun kendisi bulanık değildir ve GPU tarafından her karede yeniden bulanıklaştırılması gerekir. Kare hızının öncekinden 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ündüğü için GPU'nun, saf uygulamaya kıyasla aslında öncekinden daha fazla iş yapmasıdır.
Elde ettiğimiz sonuç pek güzel değil ancak animasyonu son derece hızlı hale getiriyor. Bulanıklaştırılacak öğenin tanıtımını yapmamaya geri döneriz. Bunun yerine, üst düzey bir 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. Demo'nun yavaşlamasının nedeni budur. Öğe bulanıklaştırılmış ancak yükseltilmemişse bulanıklık, bunun yerine en yakın üst öğe dokusuna rasterleştirilir. Bizim durumumuzda bu, tanıtılan üst sarmalayıcı öğedir. Bulanıklaştırılmış resim artık üst öğenin dokusudur ve gelecekteki tüm kareler için yeniden kullanılabilir. Bu yöntem yalnızca bulanık öğelerin animasyonlu olmadığını ve bunları önbelleğe almanın yararlı olduğunu bildiğimiz için işe yarar. Bu tekniğin uygulandığı bir demo aşağıda verilmiştir. Moto G4 bu yaklaşımı nasıl değerlendiriyor? Spoiler uyarısı: Telefonunuzun bu konudaki fikri:
Artık GPU'da çok fazla boşluk var ve 60 fps'de sorunsuz bir deneyim sunuyoruz. Başardık.
Üretime alma
Demomuzda, içeriğin kopyalarının farklı yoğunluklarda bulanıklaştırılması için bir DOM yapısını birden çok kez kopyaladık. Yazarın CSS stillerinde veya hatta JavaScript'inde istenmeyen yan etkileri olabileceğinden, bunun üretim ortamında nasıl çalışacağını merak edebilirsiniz. Doğru. Gölge DOM'u girin.
Çoğu kişi Gölge DOM'u Özel Öğeleri'ne "dahili" öğeler eklemenin bir yolu olarak düşünür. Ancak Gölge DOM, yalıtım ve performans için de kullanılabilir. 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 rasterize edilmesi için zaten bir <div>
öğemiz var ve artık bu <div>
öğelerini gölge ana makineler olarak kullanıyoruz. attachShadow({mode: 'closed'})
kullanarak bir ShadowRoot
oluştururuz ve içeriğin kopyasını <div>
yerine ShadowRoot
'e ekleriz. Kopyalarımızın orijinaliyle aynı şekilde biçimlendirilmesini sağlamak için tüm stil sayfalarını ShadowRoot
'e de kopyalamamız gerekir.
Bazı tarayıcılar Gölge DOM v1'i desteklemez. Bu tarayıcılarda, içeriği kopyalayıp hiçbir şeyin bozulmaması için dua ederiz. ShadyCSS ile Shadow DOM polyfill'i kullanabilirdik ancak bunu kitaplığımıza uygulamadık.
İşte bu kadar. Chrome'un oluşturma ardışık düzenini inceledikten sonra, bulanıklıkları tarayıcılar arasında verimli bir şekilde nasıl canlandırabileceğimizi öğrendik.
Sonuç
Bu tür efektler dikkatli bir şekilde kullanılmalıdır. DOM öğelerini kopyalayıp kendi katmanlarına zorladığımız için düşük kaliteli cihazların sınırlarını zorlayabiliriz. Tüm stil sayfalarını her ShadowRoot
'ye kopyalamak da potansiyel bir performans riskidir. Bu nedenle, mantığınızı ve stillerinizi LightDOM
'daki kopyalardan etkilenmeyecek şekilde ayarlamak mı yoksa ShadowDOM
tekniğimizi kullanmak mı istediğinize karar vermeniz gerekir. Ancak bazen bu teknik, yatırım yapmaya değer olabilir. GitHub depomuzda bulunan koda ve demo'ya göz atın. Sorularınız varsa Twitter üzerinden bana ulaşabilirsiniz.