İster sevin, ister nefret edin, paralaks hep hayatımızda. Akıllıca kullanıldığında bir web uygulamasına derinlik ve incelik katabilir. Ancak sorun, paralaksı etkili bir şekilde uygulamanın zor olabileceğidir. Bu makalede, hem yüksek performans gösteren hem de tarayıcılar arası çalışan bir çözümü ele alacağız.
![Paralaks resmi.](https://developer.chrome.com/static/blog/performant-parallaxing/image/parallax-illustration-330a26c14e2fc.jpg?authuser=5&hl=tr)
Özet:
- Paralaks animasyonları oluşturmak için kaydırma etkinliklerini veya
background-position
öğesini kullanmayın. - Daha doğru bir paralaks efekti oluşturmak için CSS 3D dönüştürmelerini kullanın.
- Mobil Safari'de paralaks efektinin yayıldığından emin olmak için
position: sticky
kullanın.
Geçici çözümü kullanmak istiyorsanız UI Element Samples GitHub deposuna gidin ve Parallax yardımcı JS'sini alın. GitHub deposunda paralaks kaydırma çubuğunun canlı demosunu görebilirsiniz.
Problem paralaksörleri
İlk olarak, paralaks etkisi elde etmenin yaygın olarak kullanılan iki yoluna, özellikle de amaçlarımız için neden uygun olmadıklarına bakalım.
Kötü: Kaydırma etkinlikleri kullanılıyor
Paralaks yapmanın temel koşulu, kaydırmayla bağlantılı olmasıdır. Sayfanın kaydırma konumundaki her değişiklik için paralaks öğesinin konumu güncellenmelidir. Bu basit gibi görünse de, modern tarayıcıların önemli bir mekanizması, eşzamansız olarak çalışma yeteneğidir. Bu, bizim örneğimizde kaydırma etkinlikleri için de geçerlidir. Çoğu tarayıcıda kaydırma etkinlikleri "en iyi çaba" olarak sunulur ve kaydırma animasyonunun her karesinde sağlanacağı garanti edilmez.
Bu önemli bilgi, öğeleri kaydırma etkinliklerine göre hareket eden JavaScript tabanlı bir çözümden neden kaçınmamız gerektiğini açıklar: JavaScript, paralaksın sayfanın kaydırma konumuna uygun olacağını garanti etmez. Mobile Safari'nin eski sürümlerinde, kaydırma etkinlikleri aslında kaydırmanın sonunda gerçekleşiyordu. Bu da JavaScript tabanlı bir kaydırma efektinin oluşturulmasını imkansız hale getiriyordu. Daha yeni sürümler, animasyon sırasında kaydırma etkinlikleri gerçekleştirir, ancak Chrome'a benzer şekilde, "en iyi çaba" esasına göre hareket eder. Ana iş parçacığı başka bir işle meşgulse kaydırma etkinlikleri hemen teslim edilmez. Bu da paralaks efektinin kaybedileceği anlamına gelir.
Kötü: background-position
güncelleniyor
Kaçınmak istediğimiz bir başka durum da her kareyi boyamaktır. Birçok çözüm, paralaks görünümünü sağlamak için background-position
değerini değiştirmeye çalışır. Bu da tarayıcının sayfayı kaydırıldığında sayfanın etkilenen bölümlerini yeniden boyamasına neden olur ve bu durum, animasyonu önemli ölçüde sekteye uğratacak kadar maliyetli olabilir.
Paralaks hareketi vaadini yerine getirmek istiyorsak hızlandırılmış özellik olarak uygulanabilecek (bugün dönüşüm ve opaklığa bağlı kalma anlamına gelir) ve kaydırma etkinliklerine bağlı olmayan bir özellik istiyoruz.
3D CSS
Hem Scott Kellum hem de Keith Clark, paralaks hareketi elde etmek için CSS 3D kullanma alanında önemli çalışmalar gerçekleştirdi. Kullandıkları teknik ise şu şekilde:
overflow-y: scroll
(ve muhtemelenoverflow-x: hidden
) ile kaydırmak için bir kapsayıcı öğe oluşturun.- Aynı öğeye bir
perspective
değeri vetop left
veya0 0
olarak ayarlanmış birperspective-origin
uygulayın. - Bu öğenin alt öğelerine Z ile çeviri uygulanır ve ekrandaki boyutları etkilenmeden paralaks hareketi sağlayacak şekilde ölçeklendirilir.
Bu yaklaşım için CSS aşağıdaki gibidir:
.container {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: scroll;
perspective: 1px;
perspective-origin: 0 0;
}
.parallax-child {
transform-origin: 0 0;
transform: translateZ(-2px) scale(3);
}
Aşağıdaki gibi bir HTML snippet'i varsayılır:
<div class="container">
<div class="parallax-child"></div>
</div>
Perspektif için ölçek ayarlanıyor
Alt öğeyi geri itmek, perspektif değeriyle orantılı olarak daha küçük hale gelmesine neden olur. Şu denklemle ne kadar ölçeklenmesi gerektiğini hesaplayabilirsiniz: (perspektif - mesafe) / perspektif. Büyük olasılıkla paralaks unsurunun paralaks almasını istediğimiz, ancak yazıldığı boyutta göründüğü için olduğu gibi bırakılması yerine bu şekilde ölçeklenmesi gerekir.
Yukarıdaki kodda, perspektif 1 piksel ve parallax-child
öğesinin Z mesafesi -2 piksel'dir. Bu, öğenin 3x oranında artırılması gerektiği anlamına gelir. Koda eklenen değeri görebilirsiniz: scale(3)
.
translateZ
değeri uygulanmamış içerikler için sıfır değerini kullanabilirsiniz. Bu da ölçeğin (perspektif - 0) / perspektif (perspektif) olduğu anlamına gelir. Bu da 1 değerini verir. Diğer bir deyişle, ölçeğin artırılıp azaltılmadığı anlamına gelir. Çok kullanışlı, gerçekten.
Bu yaklaşımın işleyiş şekli
Bu yöntemin neden işe yarayacağını net bir şekilde bilmek önemlidir, çünkü bu bilgiyi kısa süre içinde kullanacağız. Kaydırma etkili bir şekilde bir dönüşümdür, bu yüzden hızlandırılabilir. Çoğunlukla katmanların GPU ile yerlerinin değiştirilmesini içerir. Perspektif kavramı olmayan tipik bir kaydırma işleminde, kaydırma öğesi ile alt öğeleri karşılaştırılırken kaydırma bire bir şekilde gerçekleşir.
Bir öğeyi 300px
kadar aşağı kaydırırsanız alt öğeleri de aynı miktarda yukarı dönüştürülür: 300px
.
Bununla birlikte, kaydırma öğesine bir perspektif değeri uygulamak bu süreçte karışıklığa yol açar; kaydırma dönüşümünün temelini oluşturan matrisleri değiştirir.
300 piksellik bir kaydırma, seçtiğiniz perspective
ve translateZ
değerlerine bağlı olarak artık alt öğeleri yalnızca 150 piksel hareket ettirebilir. Bir öğenin translateZ
değeri 0 ise öğe 1:1'de (eski adıyla) kaydırılır. Ancak Z'de belirtilenden uzağa itilen bir çocuk, perspektif kaynağından uzağa kaydırılır. Net sonuç: paralaks hareket. En önemlisi de bu, otomatik olarak tarayıcının dahili kaydırma makinesinin bir parçası olarak işlenir. Böylece scroll
etkinliklerini dinleme veya background-position
değişikliği gerekmez.
Mermer sinek: Mobile Safari
Her efektlerle ilgili uyarılar vardır ve dönüşümler için önemli olanlardan biri, 3D efektlerin alt öğelerde korunmasıyla ilgilidir. Perspektifi olan öğe ile paralaks yapan alt öğeleri arasındaki hiyerarşide öğeler varsa 3D perspektif "düzeltilmiş" olur, yani etkinin kaybolur.
<div class="container">
<div class="parallax-container">
<div class="parallax-child"></div>
</div>
</div>
Yukarıdaki HTML'de .parallax-container
yenidir ve perspective
değerini etkili bir şekilde birleştirir ve paralaks etkisini kaybederiz. Çoğu durumda çözüm oldukça basittir: Öğeye transform-style: preserve-3d
eklerseniz ağacın daha yukarılarına uygulanan 3D efektlerini (perspektif değerimiz gibi) yaymasını sağlarsınız.
.parallax-container {
transform-style: preserve-3d;
}
Ancak Mobile Safari söz konusu olduğunda işler biraz daha karmaşıktır.
Container öğesine overflow-y: scroll
uygulamak teknik olarak çalışır ancak kaydırma öğesini hızlıca kaydırma maliyetine bağlıdır. Çözüm -webkit-overflow-scrolling: touch
eklemektir ancak perspective
öğesi de düzeltilir ve paralaks işlemi uygulanmaz.
Progresif geliştirmeler açısından bakıldığında bu, büyük olasılıkla çok büyük bir sorun değildir. Her durumda paralaks uygulayamıyorsak uygulamamız çalışmaya devam edecektir. Ancak bir çözüm bulmak faydalı olacaktır.
position: sticky
kurtarın!
Aslında, öğelerin görüntü alanının üst kısmına veya kaydırma sırasında belirli bir üst öğeye "sapmasını" sağlayan position: sticky
biçiminde bazı yardımlar vardır. Özelliklerin çoğu gibi oldukça kapsamlı, ancak içinde de küçük bir cevher var:
Bu, ilk bakışta çok fazla bir anlam ifade etmeyebilir Diğer bir deyişle, yapışkan öğeyi hareket ettirecek mesafe (başka bir öğeye veya görüntü alanına bağlı görünmesi için) sonra değil, başka dönüştürme işlemleri uygulanmadan önce hesaplanır. Bu, önceki kaydırma örneğinde olduğu gibi, ofset 300 pikselde hesaplandıysa bu 300 piksellik ofset değerini yapışkan öğelere uygulanmadan önce manipüle etmek için perspektifleri (veya başka bir dönüşümü) kullanmak için yeni bir fırsat ortaya çıkar.
Paralaks oluşturma öğesine position: -webkit-sticky
uygulayarak -webkit-overflow-scrolling:
touch
düzleştirme etkisini etkili bir şekilde "ters çevirebiliriz". Bu, paralaks öğesinin bir kaydırma kutusuyla en yakın üst öğeye (bu örnekte .container
) başvurmasını sağlar. Ardından, öncekine benzer şekilde .parallax-container
, perspective
değerini uygular. Bu değer, hesaplanan kaydırma ofsetini değiştirir ve paralaks efekti oluşturur.
<div class="container">
<div class="parallax-container">
<div class="parallax-child"></div>
</div>
</div>
.container {
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.parallax-container {
perspective: 1px;
}
.parallax-child {
position: -webkit-sticky;
top: 0px;
transform: translate(-2px) scale(3);
}
Bu sayede Mobile Safari için paralaks efekti geri yüklenir ve her şey için çok iyi bir haber olur!
Yapışkan konumlandırma uyarıları
Ancak burada bir fark vardır: position: sticky
paralaks mekaniğini değiştirir. Yapışkan konumlandırma, öğeyi kayan kapsayıcıya yapıştırmaya çalışırken yapışkan olmayan sürümlerde bunu yapmaz. Yani, yapışkanlı paralaks, içermeyen paralaksın tersidir:
position: sticky
kullanıldığında öğe, z=0 değerine ne kadar yakın olursa daha az hareket eder.position: sticky
olmadığında, öğe z=0'a ne kadar yakın olursa o kadar çok hareket eder.
Bütün bunlar biraz soyut görünüyorsa, Robert Flack'in yaptığı bu demoya göz atın. Bu demoda öğelerin yapışkan konumlandırma ile ve sabit konumlama olmadan nasıl farklı davrandığı gösterilmektedir. Farkı görmek için Chrome Canary (yazma sırasındaki sürüm 56) veya Safari'ye ihtiyacınız vardır.
![Paralaks perspektifi ekran görüntüsü](https://developer.chrome.com/static/blog/performant-parallaxing/image/parallax-perspective-scre-e5a0b46e4d2ad.jpg?authuser=5&hl=tr)
position: sticky
'nin paralaks kaydırmayı nasıl etkilediğini gösteren, Rober Flack tarafından sunulan bir demo.
Çeşitli hatalar ve geçici çözümler
Yine de her şeyde olduğu gibi, yine de düzeltilmesi gereken yumrular ve çıkıntılar vardır:
- Sürekli destek tutarsız. Chrome'da destek uygulanmaya devam ediyor, Edge'de hiç destek yok ve Firefox'ta yapışkan yapışkan perspektif dönüşümleriyle birleştirildiğinde boyama hataları var. Bu tür durumlarda, sadece gerektiğinde
position: sticky
(-webkit-
önekli sürüm) eklemek, yani sadece Mobile Safari için küçük bir kod eklemekte fayda vardır. - Efekt, Edge'de "sadece çalışmıyor". Edge, kaydırma işlemini işletim sistemi düzeyinde yapmaya çalışıyor. Bu genellikle iyi bir şeydir ancak bu durumda, kaydırma sırasında perspektif değişikliklerini algılamasını engeller. Bu sorunu düzeltmek için sabit konum öğesi ekleyebilirsiniz. Bunun nedeni, Edge'nin işletim sistemi olmayan bir kaydırma yöntemine geçmesini sağlar ve perspektif değişikliklerini hesaba katmasını sağlar.
- "Sayfanın içeriği çok arttı!" Birçok tarayıcı, sayfa içeriğinin ne kadar büyük olduğuna karar verirken ölçeği hesaba katar, ancak maalesef Chrome ve Safari bakış açısını hesaba katmamaktadır. Dolayısıyla, bir öğeye 3x ölçeği uygulanmışsa kaydırma çubukları ve benzerleri,
perspective
uygulandıktan sonra öğe 1x değerinde olsa bile görebilirsiniz. Öğeleri sağ alt köşeden (transform-origin: bottom right
ile) ölçeklendirerek bu sorunu çözmek mümkündür. Çünkü büyük boyutlu öğelerin, kaydırılabilir alanın "negatif bölgesinde" (genellikle sol üstte) büyümesine neden olur. Kaydırılabilir bölgeler, negatif bölgedeki içeriği görmenize veya içeriklere gitmenize hiçbir zaman izin vermez.
Sonuç
Paralaks, dikkatli bir şekilde kullanıldığında eğlenceli bir efekttir. Gördüğünüz gibi, bu özelliği yüksek performans gösteren, kaydırmaya bağlı ve tarayıcılar arası bir şekilde uygulamak mümkündür. Bu yöntemde, istenilen etkiyi elde etmek için biraz matematiksel hareket ve küçük bir standart metin yer almaktadır. Bu yüzden, UI Element Samples GitHub depomuzda bulabileceğiniz küçük bir yardımcı kitaplık ve örneği hazırladık.
Biraz oynayıp konu hakkında bize bilgi verin.