Bazen tasarımcıların sonunda sizin ilginizi çekecek aptalca fikirleri olur. Bir kullanıcı sayfayı kaydırdığında zıt yönlerde hareket eden öğelerden oluşan sütunlar oluşturmak zorunda kaldığım bu konseptte bu başıma geldi.
CodePen Yerleştirme Geri Dönüşü
Not: Bu demo azaltılmış hareket ayarlarına uygundur, dolayısıyla efekti görmek için hareketi etkinleştirmeniz gerekir. Ben bunu yazarken Chrome ve Safari desteğine bakıyoruz.
Modern CSS özellikleri, özellikle de kaydırma odaklı animasyonlar sayesinde bu aslında düşündüğünüz kadar zor değil. Sadece bu değil, aynı zamanda yapımı da eğlenceli! Size bu konuya nasıl yaklaştığımı göstereyim; belki siz de bunu nasıl farklı şekilde yapacağınızı paylaşmak istersiniz.
Uzmanların Görüşleri
HTML bir ana öğeden ( .opposed-columns ), onun alt öğelerinden ( .opposed-column ) ve alt öğelerinden ( .opposed-item ) oluşur:
İşaretlemede ihtiyacımız olan tek şey bu. Gerisini CSS halledecek!
Gelecekte Ne Bekleniyor?
Ana kapsayıcıyı şekillendirme
Öncelikle, bu efektin yalnızca daha büyük ekranlara uygulanmasını sağlayacak şekilde ayarlamalar yapacağız; bunun gibi bir şeyi daha küçük ekranlarda desteklemenin gerçek bir anlamı yok çünkü efekt için ek alana ihtiyacımız var.
/* Sadece daha büyük ekranlarda */ @media screen ve (width >= 50rem) { .opposed-columns { display: flex; boşluk: 2rem; max-inline-size: min(90dvi, 50rem); satır içi kenar boşluğu: otomatik; } }
Nasıl Önlem Alınmalı?
Bir “maskeleme” efekti ayarlama
Sistem Güvenliği
Her .opposition-column'daki öğelerin, kaydırıldıkça kaybolduğu yanılsamasını elde etmek için ana kapsayıcıyla birkaç şey daha yapmamız gerekiyor. Dış sütunlardaki öğeler kaydırma sırasında yukarı doğru, orta sütundaki öğeler ise aşağı doğru hareket eder. Ebeveynlerin sınırlarını aştıkça onların bir nevi yok olmasını istiyoruz.
Yani birkaç şey yapacağız. Öncelikle belgenin tamamına bir arka plan rengi değişkeni ayarlayacağız:
Teknik Analiz
@media ekranı ve (genişlik >= 50rem) { :root { --opposed-bg: lightcyan; arka plan rengi: var(--karşıt-bg); } .opposed-columns { /* öncekiyle aynı stiller */ } }
İkinci olarak, aynı arka plan rengini ebeveynin :before ve :after sözde öğelerine uygulayacağız:
Önemli Gelişmeler
@media ekranı ve (genişlik >= 50rem) { :root { --opposed-bg: lightcyan; arka plan rengi: var(--karşıt-bg); } .opposed-columns { /* öncekiyle aynı stiller */ &:önce, &:sonra { içerik: ""; konum: mutlak; satır içi iç metin: 0; blok boyutu: calc(var(--opposed-mask) * 3); işaretçi olayları: yok; z-endeksi: 1; } } }
Detaylar ve Etkileri
Sahteler üzerinde bir yığın bağlamı oluşturduğumuza ve onları ebeveyn ve onun alt öğelerinin bir katman üstüne yerleştirdiğimize dikkat edin. Bu, her sütundaki öğelerin kapsayıcıya girip çıkarken maskelenmesinin anahtarıdır. Öğeler teknik olarak sahte maskelerin altına kayıyor.
Bahsi geçmişken, ana öğe ile üç sütun arasına dikey boşluk ekleyen --opposed-mask adında başka bir değişken oluşturalım:
@media ekranı ve (genişlik >= 50rem) { :root { --opposed-bg: lightcyan; --karşıt-maske: 3rem; arka plan rengi: var(--karşıt-bg); } .karşıt-sütunlar { display: flex; boşluk: 2rem; max-inline-size: min(90dvi, 50rem); satır içi kenar boşluğu: otomatik; kenar boşluğu bloğu: var(--karşıt-mask, 3rem); konum: göreceli; } }
Sonuç ve Değerlendirme
Aynı şeyi ebeveynlerin sahtelerine de yapalım, blok boyutlarına yalnızca üçün katları ile --opposition-mask uygulayalım. Bu şekilde ebeveyn ile aralarında ilave dikey boşluk olur.
@media ekranı ve (genişlik >= 50rem) { :root { --opposed-bg: lightcyan; --karşıt-maske: 3rem; arka plan rengi: var(--karşıt-bg); } .opposed-columns { /* öncekiyle aynı stiller */ &:önce, &:sonra { içerik: ""; konum: mutlak; satır içi iç metin: 0; blok boyutu: calc(var(--opposed-mask) * 3); işaretçi olayları: yok; z-endeksi: 1; } } }
Bunun nereye varacağını görebilirsiniz. Ana konteyner ile onun sahteleri arasında oldukça fazla boşluk var. Sütun öğelerinin, ana kapsayıcının dışına kaydırıldıkça soluklaşıyormuş gibi görünmesini istiyoruz. Onların opaklığıyla veya buna benzer bir şeyle uğraşmamıza gerek yok. Bunun yerine sahtelerin üzerine arka plan degradeleri ekleyebiliriz.
:before sözde kapsayıcının üst kısmında olduğundan, ona belgenin temel arka plan rengiyle eşleşen düz bir renkten şeffaf, yukarıdan aşağıya doğru giden bir degrade vereceğiz. :after sözde ana kabın altında yer aldığından, degradeyi tersine çevirerek belgenin arka plan rengine göre aşağıdan yukarıya şeffaf olmasını sağlayacağız.
@media screen and (width >= 50rem) { :root { /* öncekiyle aynı stiller */ } .opposed-columns { /* öncekiyle aynı stiller */ &:before, &:after { /* öncekiyle aynı stiller */ } &:before { arka plan görüntüsü: lineer-gradient( to Bottom, var(--opposed-bg) var(--opposed-mask), Transparent ); iç metin bloğu-başlangıç: calc(var(--opposed-mask) * -1); } &:after { arka plan görüntüsü: doğrusal-gradient( to top, var(--opposed-bg) var(--opposed-mask), şeffaf ); iç metin bloğu sonu: calc(var(--opposed-mask) * -1); } } } }
Sihire geçmeden önce her sütundaki öğeleri yerleştirmeliyiz. Her sütun, esnek bir kapsayıcı olan ebeveynin içindeki esnek bir öğedir. Küçülmelerine ( flex-shrink: 1 ) ve büyümelerine ( flex-grow: 1 ) izin vereceğiz ve boyutu belirli bir noktada sınırlayacağız ( flex-basis: 10rem ).
Tüm bunları esnek kısayol özelliğiyle tanımlayabiliriz:
@media screen and (width >= 50rem) { /* öncekiyle aynı stiller */ .opposed-column { flex: 1 1 10rem; } }
Artık bu sütunların ızgara kapsayıcıları olmasını istiyorum, böylece boşluk özelliğini öğeler arasına boşluk eklemek için kullanabilirim:
@media screen and (width >= 50rem) { /* öncekiyle aynı stiller */ .opposed-column { flex: 1 1 10rem; ekran: ızgara; boşluk: 2rem; } }
Gap'a erişim sağlamak için Flexbox'ı burada da kesinlikle kullanabilirdik, ancak varsayılan düzen satır olarak ayarlanmıştır ve bunu sütun olarak geçersiz kılmamız gerekir. Grid bu durumda biraz daha kısadır.
Bunun için geldin, değil mi? Her şeyi, sütun öğelerinin kaydırma sırasında ana kapsayıcıya girip çıkabileceği şekilde ayarladık. Şimdi bu kaydırma davranışını eklememiz gerekiyor.
Animasyon zaman çizelgesi özelliğinin gerçekten kullanışlı olduğu yer burasıdır. Normalde bir CSS animasyonu kendi başına çalışır. Sayfa yüklendiğinde (veya belirlediğiniz belirli bir gecikme sonrasında) başlar ve süreyi belirlediğiniz süre kadar sonra sona erer. Animation-timeline ile animasyonun kaydırma konumuna göre çalışmasını söyleriz... dolayısıyla "kaydırma odaklı" animasyon terimi de buradan gelir.
Burada desteklenen iki fonksiyonumuz var: Scroll() ve view(). İlgilidirler ancak çok farklıdırlar. Scroll() animasyonu bir öğenin kaydırma konumuna göre çalıştırır. view() işlevi de benzerdir ancak öğenin ilerlemesini kaydırma portuna (yani içinde bulunduğu kabın kaydırılabilir alanına) girip çıkarken izler.
view() işlevini kullanacağız çünkü bunu ana kapsayıcının içinde kaydırılabilir net bir alanın olduğu yere ayarladık. Animasyonu sütun öğelerinin kaydırma konumuna göre değil, o alana girip çıktığı yere göre çalıştırmamız gerekiyor.
Bu gerçekten ilginç çünkü view()'a animasyonun kaydırılabilir alana girdiğinde tam olarak nerede başlamasını istediğimizi ve aynı alandan çıktığında nerede durması gerektiğini söyleyebiliriz. Bunun gibi:
/* Resmi sözdizimi */ animasyon-zaman çizelgesi: view([
Eksenleri tanımlayarak başlayalım:
@media ekranı ve (genişlik >= 50rem) { /* öncekiyle aynı stiller */ .opposed-column { /* ... */ Animation-timeline: view(); animasyon aralığı: giriş kapağı; } }
İstediğimiz kısmen bu, ancak şunu söylüyoruz: animasyonun (1) kaydırma alanına (giriş) girdiği anda başlamasını ve (2) alanı tamamen terk ettiğinde (kapak) bitmesini istiyoruz. İç metinler hakkında açık bir şekilde konuşmamız gerekiyor çünkü animasyonun aralığını, girdiği ve çıktığı yere göre belirleyen şey budur. Tüm aralığı istiyoruz, dolayısıyla giriş %0'da başlar ve çıkış, bir öğe %100'de kapsandığında gerçekleşir.
@media ekranı ve (genişlik >= 50rem) { /* öncekiyle aynı stiller */ .opposed-column { /* ... */ Animation-timeline: view(); animasyon aralığı: giriş %0, %100'ü kapsar; } }
Son olarak, animasyonu doğrusal olarak çalışacak şekilde ayarlayacağız; öğelerin kaydırıldıkça yavaşlamasına veya azalmasına gerek yok.
@media ekranı ve (genişlik >= 50rem) { /* öncekiyle aynı stiller */ .opposed-column { /* ... */ animasyon-zamanlama-işlevi: doğrusal; animasyon-zaman çizelgesi: view(); animasyon aralığı: giriş %0, %100'ü kapsar; } }
Tamam, harika. Ancak yapmadığımız şey bir animasyon oluşturmaktı. Çalışırken ne yapmasını istediğimizi ayarladık ama asıl hareketi tanımlamamız gerekiyor.
Üç ayrı CSS animasyonu ayarlamak istiyorum:
Bir tane ilk sütundaki öğeleri yukarıya çevirir (taşır). Bu, diğer sütundaki öğeler için ilk animasyonun tersidir.
Teknik olarak ilk animasyonu her iki dış sütuna da ayarlayabiliriz, ancak ben ilkinden biraz kaydırılmış üçüncü bir animasyon istiyorum, böylece bu sütunlar kademeli olarak görünür.
@keyframes kaydırma1 { from { transform: TranslateY(var(--opposed-mask)); } - { transform: TranslateY(calc(var(--opposed-mask) * -1)); } } @ana kareler kaydırma2 { from { transform:translateY(calc(var(--opposed-mask) * -1)); } - { transform: TranslateY(var(--opposed-mask)); } } @ana kareler kaydırma3 { from { transform:translateY(calc(var(--opposed-mask) * .66)); } - { transform: TranslateY(calc(var(--opposed-mask) * -.33)); } }
Elbette güncellememiz gerekirse bunlar için değişkenler oluşturabiliriz:
@media ekranı ve (genişlik >= 50rem) { :root { --opposed-bg: lightcyan; --karşıt-maske: 3rem; --animasyon-1: kaydırma1; --animasyon-2: kaydırma2; --animasyon-3: kaydırma3; /* ... */ } }
…ve bunları her sütuna uygulayın:
@media screen and (width >= 50rem) { /* öncekiyle aynı stiller */ .opposed-column { /* öncekiyle aynı stiller */ } :where(.opposed-column:nth-of-type(1)) { animasyon-adı: var(--animation-1); } :where(.opposed-column:nth-of-type(2)) { animasyon-adı: var(--animasyon-2); } :where(.opposed-column:nth-of-type(3)) { animasyon-adı: var(--animasyon-3); } }
Hazır bu arada, kullanıcının azaltılmış hareket ayarlarına uymak için animasyonları devre dışı bırakmalıyız (ve maskeyi kaldırmalıyız, aksi takdirde tuhaf görünebilir):
@media (azaltılmış hareketi tercih eder: azalt) { .karşıt sütun { animasyon: ayarlanmamış; &:önce, &:sonra { içerik: unset; } } }
Yani evet, kaydırmayla yönlendirilen animasyonlar gerçekten çok harika. Ben bunu yazarken hala Firefox desteğini bekliyoruz, ancak kaydırma açıklamalarını kullanan varsayılan bir deneyim sağlamak ve ardından normal bir animasyon zaman çizelgesinde çalıştırmak gibi, desteklemeyen tarayıcılar için bir geri dönüş deneyimi ayarlamak için bunu kesinlikle @supports içine sarabilirsiniz:
@destekler (animasyon-zaman çizelgesi: view()) { /* ... */ }
Bu elbette kaydırma odaklı animasyonların neler yapabileceğine kısa bir bakış. Ne tür şeyler yaptınız veya denediniz? Yoksa bu duruma farklı mı yaklaşırsınız? Bana bildirin!