Özet
İşte sır: Bir sonraki uygulamanızda scroll
etkinliklerine ihtiyacınız olmayabilir. Bir
IntersectionObserver
,
position:sticky
öğeleri sabitlendiğinde veya sabitlenmeyi bıraktığında özel etkinlikleri nasıl tetikleyebileceğinizi gösteriyorum. Şunlar olmadan:
kullanımından bahsedeceğiz. Bunu kanıtlayacak harika bir demo bile var:
Karşınızda sticky-change
etkinliği
CSS sabit konumunu kullanmanın pratik sınırlamalarından biri, mülkün etkin olup olmadığını gösteren bir platform sinyali sağlamaz. Başka bir deyişle, bir öğenin ne zaman yapışkan hale geleceğini veya ne zaman yapışkan kalmayı bırakır.
Aşağıdaki örneği ele alalım. Bu örnekte, <div class="sticky">
üst kapsayıcısının üstüne yerleştirin:
.sticky {
position: sticky;
top: 10px;
}
Öğeler bu işarete çarptığında tarayıcının bunu bildirmesi güzel olmaz mıydı?
Sadece ben değilim
büyük önem taşıyor. position:sticky
sinyali bir dizi kullanım alanının kilidini açabilir:
- Sabitlenen banner'a gölge uygulayabilirsiniz.
- Bir kullanıcı içeriğinizi okurken, takip edebilirsiniz.
- Kullanıcı sayfayı kaydırırken kayan TOC widget'ını bölümüne bakın.
Bu kullanım alanlarını göz önünde bulundurarak bir nihai hedef belirledik:
bir position:sticky
öğesi sabitlendiğinde tetiklenir. Biz buna
sticky-change
etkinlik:
document.addEventListener('sticky-change', e => {
const header = e.detail.target; // header became sticky or stopped sticking.
const sticking = e.detail.stuck; // true when header is sticky.
header.classList.toggle('shadow', sticking); // add drop shadow when sticking.
document.querySelector('.who-is-sticking').textContent = header.textContent;
});
Demo, sabit hale geldiklerinde alt gölge olarak bu etkinliğe dönüştürebilir. Ayrıca yeni bir başlık görürsünüz.
Kaydırma etkinlikleri olmayan kaydırma efektleri?
Bu adlara referans verebilmek için biraz terminolojiyi keselim. yazın:
- Kayan kapsayıcı - "blog yayınları" listesidir.
- Başlıklar -
position:sticky
içeren her bölümde mavi başlık. - Yapışkan bölümler: Her içerik bölümü. Ekranın altında kayan metin yapışkan başlıklar.
- "Sabit mod" - öğeye
position:sticky
uygulanırken.
Hangi üstbilginin "yapışkan moda" girdiğini öğrenmek için bunu
kayan kapsayıcının kaydırma ofseti. Bu da bize, projenin
gösterilen başlığı hesaplamak için kullanılır. Ancak bu durum oldukça
scroll
etkinlikleri olmadan yapmak zordur :) Diğer sorun ise
position:sticky
, düzeltildiğinde öğeyi düzenden kaldırır.
Dolayısıyla, kaydırma etkinlikleri olmadan düzenle ilgili işlemleri gerçekleştirme yeteneğini hesaplamalar yapabilir.
Kaydırma konumunu belirlemek için model DOM ekleniyor
Şunu yapmak için scroll
etkinlikleri yerine IntersectionObserver
kullanacağız:
başlıkların sabit moda girip çıkmayacağını belirler. İki düğüm ekleme
(biri üstte, diğeri üstte olmak üzere) her yapışkan bölüme
kaydırıcılar, kaydırma konumunu bulmak için ara nokta görevi görür. Bu durumlarda
işaretçilerin kapsayıcıya girmesine veya kapsayıcıdan ayrılmasına, görünürlüklerinin değişmesi
Kesişim Gözlemcisi bir geri çağırma tetikler.
Yukarı ve aşağı kaydırma ile ilgili dört durumu kapsamak için iki koruyucuya ihtiyacımız var:
- Aşağı kaydırma: Başlık, üst koruyucunun üst çizgisi çakıştığında yapışkan hale gelir üst kısmına yerleştirin.
- Aşağı kaydırma: başlık, sayfanın en altına ulaştığında sabit moddan çıkar bölümünün ve alt kısmındaki koruyucunun, kapsayıcının üst tarafından kesiştiğini unutmayın.
- Yukarı kaydırma: Başlık, üst koruyucu kaydırıldığında yapışkan moddan çıkar yukarıdan görünüme geri dönebilir.
- Yukarı kaydırma: Başlık, alt koruyucunun arkası kesişirken yapışkan hale gelir yukarıdan görebilirsiniz.
Ekran video kaydını gerçekleşme sırasına göre 1'den 4'e kadar görüntülemek faydalıdır:
CSS
Nöbetçiler her bölümün üst ve alt kısmına yerleştirilir.
.sticky_sentinel--top
, başlığın üzerinde yer alır.
.sticky_sentinel--bottom
, bölümün alt kısmında yer alır:
:root {
--default-padding: 16px;
--header-height: 80px;
}
.sticky {
position: sticky;
top: 10px; /* adjust sentinel height/positioning based on this position. */
height: var(--header-height);
padding: 0 var(--default-padding);
}
.sticky_sentinel {
position: absolute;
left: 0;
right: 0; /* needs dimensions */
visibility: hidden;
}
.sticky_sentinel--top {
/* Adjust the height and top values based on your on your sticky top position.
e.g. make the height bigger and adjust the top so observeHeaders()'s
IntersectionObserver fires as soon as the bottom of the sentinel crosses the
top of the intersection container. */
height: 40px;
top: -24px;
}
.sticky_sentinel--bottom {
/* Height should match the top of the header when it's at the bottom of the
intersection container. */
height: calc(var(--header-height) + var(--default-padding));
bottom: 0;
}
Kavşak Gözlemcilerini Kurma
Kesişim Gözlemcileri, bir hedef öğe ve belge görüntü alanını veya bir üst kapsayıcıyı seçebilirsiniz. Bizim örneğimizde bir üst kapsayıcıyla kesişimler gözlemliyoruz.
Sihirli sos IntersectionObserver
. Her bir koruyucu
mesafedeki kesişim görünürlüğünü gözlemlemek için IntersectionObserver
kaydırma kapsayıcı. Bir koruyucu, görünür görüntü alanına kaydırıldığında
bir başlık sabitlenir veya artık yapışkan kalmaz. Benzer şekilde, bir koruyucu çıkış yaptığında
görüntü alanını değiştirebilirsiniz.
İlk olarak, üstbilgi ve altbilgi koruyucuları için gözlemcileri ayarladım:
/**
* Notifies when elements w/ the `sticky` class begin to stick or stop sticking.
* Note: the elements should be children of `container`.
* @param {!Element} container
*/
function observeStickyHeaderChanges(container) {
observeHeaders(container);
observeFooters(container);
}
observeStickyHeaderChanges(document.querySelector('#scroll-container'));
Ardından, .sticky_sentinel--top
öğeleri geçtiğinde etkinleşecek bir gözlemci ekledim
kayan kapsayıcı'nın üst kısmından (her iki yönde) dokunun.
observeHeaders
işlevi en iyi kordonları oluşturur ve
her bölüme bakın. Gözlemci, koruyucunun kesişimini
üst kısmına yerleştirilir ve görüntü alanına girip girmediğine karar verir. O
bilgisi, bölüm üstbilgisinin yapılıp yapılmadığını belirler.
/**
* Sets up an intersection observer to notify when elements with the class
* `.sticky_sentinel--top` become visible/invisible at the top of the container.
* @param {!Element} container
*/
function observeHeaders(container) {
const observer = new IntersectionObserver((records, observer) => {
for (const record of records) {
const targetInfo = record.boundingClientRect;
const stickyTarget = record.target.parentElement.querySelector('.sticky');
const rootBoundsInfo = record.rootBounds;
// Started sticking.
if (targetInfo.bottom < rootBoundsInfo.top) {
fireEvent(true, stickyTarget);
}
// Stopped sticking.
if (targetInfo.bottom >= rootBoundsInfo.top &&
targetInfo.bottom < rootBoundsInfo.bottom) {
fireEvent(false, stickyTarget);
}
}
}, {threshold: [0], root: container});
// Add the top sentinels to each section and attach an observer.
const sentinels = addSentinels(container, 'sticky_sentinel--top');
sentinels.forEach(el => observer.observe(el));
}
Gözlemci threshold: [0]
ile yapılandırıldığından hemen geri çağırması etkinleşir
görünür hale gelir.
Bu süreç, alt taraftaki koruyucuda da (.sticky_sentinel--bottom
) benzer bir süreçtir.
Altbilgiler alttan geçtiğinde etkinleşmek üzere ikinci bir gözlemci oluşturulur
kaydırma kapsayıcısının özellikleri arasındadır. observeFooters
işlevi,
sentinel düğümleri oluşturur ve bunları her bir bölüme ekler. Gözlemci
alt ile kesişimine odaklanır ve bu noktanın en iyi
veya ayrılabilir. Bu bilgiler, bölüm üstbilgisinin
uygulayıp uygulamayacağınızı belirleyin.
/**
* Sets up an intersection observer to notify when elements with the class
* `.sticky_sentinel--bottom` become visible/invisible at the bottom of the
* container.
* @param {!Element} container
*/
function observeFooters(container) {
const observer = new IntersectionObserver((records, observer) => {
for (const record of records) {
const targetInfo = record.boundingClientRect;
const stickyTarget = record.target.parentElement.querySelector('.sticky');
const rootBoundsInfo = record.rootBounds;
const ratio = record.intersectionRatio;
// Started sticking.
if (targetInfo.bottom > rootBoundsInfo.top && ratio === 1) {
fireEvent(true, stickyTarget);
}
// Stopped sticking.
if (targetInfo.top < rootBoundsInfo.top &&
targetInfo.bottom < rootBoundsInfo.bottom) {
fireEvent(false, stickyTarget);
}
}
}, {threshold: [1], root: container});
// Add the bottom sentinels to each section and attach an observer.
const sentinels = addSentinels(container, 'sticky_sentinel--bottom');
sentinels.forEach(el => observer.observe(el));
}
Gözlemci threshold: [1]
ile yapılandırıldığından
tüm düğümün görünümü
içindedir.
Son olarak, sticky-change
özel etkinliğini tetiklemek için kullanabileceğim iki yardımcı programım var
oluşturmak için şu adımları uygulayın:
/**
* @param {!Element} container
* @param {string} className
*/
function addSentinels(container, className) {
return Array.from(container.querySelectorAll('.sticky')).map(el => {
const sentinel = document.createElement('div');
sentinel.classList.add('sticky_sentinel', className);
return el.parentElement.appendChild(sentinel);
});
}
/**
* Dispatches the `sticky-event` custom event on the target element.
* @param {boolean} stuck True if `target` is sticky.
* @param {!Element} target Element to fire the event on.
*/
function fireEvent(stuck, target) {
const e = new CustomEvent('sticky-change', {detail: {stuck, target}});
document.dispatchEvent(e);
}
İşte bu kadar.
Son demo
position:sticky
içeren öğeler haline geldiğinde özel bir etkinlik oluşturduk.
scroll
etkinlik kullanılmadan sabit ve eklenmiş kaydırma efektleri var.
Sonuç
IntersectionObserver
adlı çocuğum genellikle
yardımcı olan bazı scroll
etkinliğe dayalı kullanıcı arayüzü kalıplarının yerine
zaman içinde gelişti. Cevabın evet ve hayır olduğu anlaşılıyor. Anlamsal
IntersectionObserver
API'nin kullanımı her şey için kullanımı zorlaştırır. Ama
Az önce gösterdiğim gibi bazı ilginç teknikler için kullanabilirsiniz.
Stil değişikliklerini tespit etmenin başka bir yolu nedir?
Pek sayılmaz. İhtiyacımız olan şey, bir DOM öğesindeki stil değişikliklerini gözlemlemekti. Maalesef web platformu API'lerinde aşağıdakileri yapmanıza olanak tanıyan hiçbir şey yoktur. saat stili değişiklikleri.
MutationObserver
, mantıklı bir ilk tercihtir ancak işe yaramaz.
gerekir. Örneğin, demoda sticky
bir kullanıcı geri aranırsa
sınıfı bir öğeye eklenir. Ancak öğenin hesaplanan stili değiştiğinde eklenmez.
sticky
sınıfının sayfa yükleme sırasında zaten bildirilmiş olduğunu unutmayın.
Gelecekte,
"Style Mutation Observer" (Stil Değişimi Gözlemci)
mutasyon gözlemcilerine ekleme yapmak, tablodaki değişiklikleri gözlemlemek ve
öğesinin hesaplanan stillerini
değiştirmenizi sağlar.
position: sticky
.