Scrollytelling, ilgi çekici ve sürükleyici web deneyimleri oluşturmak için kullanılan popüler bir tekniktir. Bu teknik, kullanıcı sayfayı kaydırdıkça sayfadaki öğeleri canlandırarak etkili bir şekilde hikaye anlatmayı veya kullanıcıyı bir anlatı boyunca yönlendirmeyi içerir. CSS kaydırmaya dayalı animasyonlar sayesinde bu efektleri JavaScript'e ihtiyaç duymadan doğrudan CSS'de oluşturabilirsiniz. Animasyonlar, zamana dayalı bir saatle değil, kaydırma konumuyla kontrol edilir. Bu sayede animasyonlar her zaman kullanıcının kaydırma hareketiyle senkronize olur.
Nasıl uygulanır?
Kaydırarak hikaye anlatımı deneyimi oluşturmak için iki öğe grubuna ihtiyacınız vardır: biri kaydırma konumunu izlemek, diğeri ise animasyonlu hale getirmek için.
Öncelikle, izlemek istediğiniz öğelerde adlandırılmış bir view-timeline tanımlayın. Bunlar, animasyonlarınızın sürücüleri olarak işlev görür.
#tracked {
section:nth-child(1){ view-timeline: --tl-1 block; }
section:nth-child(2){ view-timeline: --tl-2 block; }
section:nth-child(3){ view-timeline: --tl-3 block; }
section:nth-child(4){ view-timeline: --tl-4 block; }
section:nth-child(5){ view-timeline: --tl-5 block; }
}
Ardından, animasyon eklemek istediğiniz öğelere animasyon uygulayın ve animation-timeline özelliğini kullanarak bunları yeni oluşturduğunuz zaman çizelgelerine bağlayın.
#animated {
section {
animation: animate-in auto linear both, animate-out auto linear forwards;
animation-range: entry 25% cover 50%, exit 50% exit 75%;
}
section:nth-child(1){ animation-timeline: --tl-1; }
section:nth-child(2){ animation-timeline: --tl-2; }
section:nth-child(3){ animation-timeline: --tl-3; }
section:nth-child(4){ animation-timeline: --tl-4; }
section:nth-child(5){ animation-timeline: --tl-5; }
}
animation-timeline öğesinin adlandırılmış zaman çizelgelerine referans verebilmesi için aynı kapsamda olmaları gerekir. Zaman çizelgelerini, ihtiyaç duyan tüm öğeler için kullanılabilir hale getirmek üzere ortak bir üst öğede timeline-scope özelliğini kullanabilirsiniz. :root öğesi genellikle bunun için iyi bir seçimdir.
html {
timeline-scope: --tl-1, --tl-2, --tl-3, --tl-4, --tl-5;
}
Son olarak, animasyonun çalışması gereken zaman çizelgesinin tam aralığını belirtmek için animation-range özelliğini kullanabilirsiniz. Bu sayede, animasyonların ne zaman tetikleneceği ve nasıl ilerleyeceği üzerinde ayrıntılı kontrol sahibi olursunuz.
#animated section {
animation-range: entry 25% cover 50%, exit 50% exit 75%;
}
Örnek kod
html {
timeline-scope: --tl-1, --tl-2, --tl-3, --tl-4, --tl-5;
}
#tracked {
section:nth-child(1){ view-timeline: --tl-1 block; }
section:nth-child(2){ view-timeline: --tl-2 block; }
section:nth-child(3){ view-timeline: --tl-3 block; }
section:nth-child(4){ view-timeline: --tl-4 block; }
section:nth-child(5){ view-timeline: --tl-5 block; }
}
@keyframes animate-in {
from { scale: 0.5; opacity: 0; transform: rotateY(-180deg); }
to { transform: rotateY(0deg); }
}
@keyframes animate-out {
to { translate: 100% 0; opacity: 0; }
}
#animated {
section {
animation: animate-in auto linear both, animate-out auto linear forwards;
animation-range: entry 25% cover 50%, exit 50% exit 75%;
backface-visibility: hidden;
}
section:nth-child(1){ animation-timeline: --tl-1; }
section:nth-child(2){ animation-timeline: --tl-2; }
section:nth-child(3){ animation-timeline: --tl-3; }
section:nth-child(4){ animation-timeline: --tl-4; }
section:nth-child(5){ animation-timeline: --tl-5; }
}
/* MANDATORY Copy-Paste Safety: Disable continuous storytelling motion for sensitive users */
@media (prefers-reduced-motion: reduce) {
#animated section {
animation: none !important;
opacity: 1 !important;
transform: none !important;
}
}
En İyi Uygulamalar
Kaydırmaya dayalı animasyonları kullanırken sorunsuz ve erişilebilir bir deneyim sunmak için birkaç en iyi uygulamayı takip etmek önemlidir:
- ÖZELLİK algılamayı ekleyin: Tüm tarayıcılar kaydırmaya dayalı animasyonları desteklemez. Destek durumunu kontrol etmek ve desteklemeyen tarayıcılar için yedek sağlamak üzere
@supports ((animation-timeline: scroll()) and (animation-range: 0% 100%))kullanın.- Yalnızca kısmi desteği olan tarayıcıları filtrelemek için
(animation-range: 0% 100%)kontrolü buraya DAHİL EDİLMELİDİR. - Yedek strateji için
scroll-timeline-polyfillpaketini KULLANMAYIN. Bu paketin özellikleri tamamlanmamıştır ve bilinen birçok sorunu vardır. - Animasyonun yalnızca dekoratif olduğu düşünülüyorsa progresif geliştirmeyi tercih edin ve yedek SAĞLAMAYIN.
- Yalnızca kısmi desteği olan tarayıcıları filtrelemek için
- DO respect user preferences: Some users prefer to have less motion on the web. Bu kullanıcılar için animasyonlarınızı devre dışı bırakmak veya azaltmak üzere
prefers-reduced-motionmedya sorgusunu kullanın. - Yalnızca performanslı CSS özelliklerini canlandırmaya ÇALIŞIN: En akıcı animasyonlar için tarayıcının birleştirici iş parçacığı tarafından işlenebilen özellikleri (ör.
transformveopacity) canlandırın.widthveyaheightgibi diğer özellikleri canlandırmak performans sorunlarına yol açabilir. - DO Doğru bildirim sırasını kullanın:
animationkısayol özelliğini kullanırken, kısayolun zaman çizelgesini sıfırlamasını önlemek içinanimation-timelineveanimation-rangeözelliklerini sonra bildirin.
Kaydırmaya dayalı animasyon oluşturmak için view-timeline özelliğini kullanırken:
- Ad için CSS
<dashed-ident>KULLANIN. - İSTEĞE BAĞLI İzlenecek eksen konusunda net olun: Varsayılan
blockeksenini hedeflemediğinizde (ör. yatay kaydırıcıda)view-timeline-axisile hangi eksenin izleneceği konusunda net olun. - DO make sure the scope of the lookup works: When the element that is declaring the
view-timelineis not a flat tree ancestor of the animated element, hoist up the visibility of theview-timeline’s name by usingtimeline-scopeon a shared ancestor.
Yedek stratejiler
Kaydırmaya dayalı animasyonları desteklemeyen tarayıcılarda görsel efektleri yeniden oluşturmak için yedek kullanabilirsiniz. Yedekler genellikle bir kaydırma dinleyicisi (ScrollTimeline efektleri için) veya IntersectionObserver API (ViewTimeline efektleri için) ile oluşturulur.
Kaydırmaya dayalı animasyonlar için yerleşik desteğe sahip tarayıcılarda DAİMA yerel CSS uygulamasını kullanın. Bu uygulamalar daha yüksek performans sağlar.
Yedek yaklaşımı kullanılarak her efektin yeniden oluşturulamayacağını unutmayın.
Özellikle bu kullanım alanında, aşağıdaki komut dosyası, kaydırmaya dayalı animasyonları desteklemeyen tarayıcılar için yedek seçeneği uygular. Her bir #tracked section öğesinin görünürlüğünü izlemek için IntersectionObserver kullanır ve ilgili #animated section öğesinin transform özelliğini buna göre günceller.
const animatedSections = document.querySelectorAll('#animated section');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const sectionIndex = Array.from(document.querySelectorAll('#tracked section')).indexOf(entry.target);
if (sectionIndex !== -1) {
const animatedSection = animatedSections[sectionIndex];
const ratio = entry.intersectionRatio;
// Animate-in
animatedSection.style.opacity = ratio;
animatedSection.style.transform = `scale(${0.5 + ratio * 0.5}) rotateY(${-180 + ratio * 180}deg)`;
// Animate-out
if (ratio < 0.5) {
animatedSection.style.translate = `${(0.5 - ratio) * 2 * 100}% 0`;
} else {
animatedSection.style.translate = '0 0';
}
}
});
}, { threshold: Array.from({length: 101}, (_, i) => i / 100) });
document.querySelectorAll('#tracked section').forEach(section => {
observer.observe(section);
});
Ve beraberindeki CSS:
#animated section {
opacity: 0;
transform: scale(0.5) rotateY(-180deg);
backface-visibility: hidden;
}
/* MANDATORY Copy-Paste Safety: Ensure content remains fully visible and legible for assistive technologies or users with motion sensitivities */
@media (prefers-reduced-motion: reduce) {
#animated section {
opacity: 1 !important;
transform: none !important;
translate: 0 0 !important;
}
}
Bu yedek, yerel CSS özelliğini desteklemeyen tarayıcılar için daha doğru, kaydırmaya dayalı bir animasyon sağlayarak tüm kullanıcılara daha tutarlı bir deneyim sunar. IntersectionObserver için bir dizi eşik kullanarak kaydırma konumunu daha hassas bir şekilde izleyebilir ve daha akıcı bir animasyon oluşturabiliriz.