iOS ve Android uygulamalarındakine benzer bir sekme bileşeni oluşturmaya dair temel bir genel bakış.
Bu gönderide, web için duyarlı, birden çok cihaz girişini destekleyen ve tüm tarayıcılarda çalışan bir Sekme bileşeni oluşturma konusundaki düşüncenizi paylaşmak istiyorum. Demoyu deneyin.
Videoyu tercih ediyorsanız bu yayının YouTube sürümünü burada bulabilirsiniz:
Genel Bakış
Sekmeler, tasarım sistemlerinin yaygın bir bileşenidir ancak birçok şekil ve biçimde olabilir. Önce <frame>
öğesine dayalı masaüstü sekmeleri vardı, şimdi ise içeriği fizik özelliklerine göre animasyonlu hale getiren akıcı mobil bileşenlerimiz var.
Hepsi aynı şeyi yapmaya çalışıyor: Yer kazanmak.
Günümüzde sekme kullanıcı deneyiminin temel unsuru, ekran çerçevesindeki içeriğin görünürlüğünü değiştiren bir düğme gezinme alanıdır. Birçok farklı içerik alanı aynı alanı paylaşır, ancak gezinmede seçilen düğmeye göre koşullu olarak sunulur.
Web Taktikleri
Web platformunun bazı önemli özellikleri sayesinde bu bileşeni oluşturmanın oldukça kolay olduğunu gördüm:
- Uygun kaydırma durak konumlarıyla zarif kaydırma ve klavye etkileşimleri için
scroll-snap-points
- Tarayıcı tarafından yönetilen sayfa içi kaydırma sabitleme ve paylaşım desteği için URL karmaları aracılığıyla derin bağlantılar
<a>
veid="#hash"
öğe işaretlemeleriyle ekran okuyucu desteği- Çapraz geçişleri ve anında sayfa içi kaydırmayı etkinleştirmek için
prefers-reduced-motion
- Seçilen sekmenin dinamik olarak altını çizmek ve rengi değiştirmek için kullanılan taslak
@scroll-timeline
web özelliği
HTML
Buradaki temel kullanıcı deneyimi şudur: Bir bağlantıyı tıklayın, URL'nin iç içe yerleştirilmiş sayfa durumunu temsil etmesini sağlayın ve ardından tarayıcı eşleşen öğeye ilerlerken içerik alanının güncellendiğini görün.
İçerikte bazı yapısal içerik üyeleri vardır: bağlantılar ve :target
'ler. <nav>
için mükemmel olan bağlantıların listesine ve <section>
için mükemmel olan <article>
öğelerinin listesine ihtiyacımız var. Her bağlantı karması bir bölümle eşleşir ve tarayıcı, öğeleri sabitleme yoluyla kaydırır.
Örneğin, bir bağlantıyı tıkladığınızda Chrome 89'da :target
makalesi otomatik olarak odaklanır. JS gerekmez. Kullanıcı daha sonra giriş cihazını kullanarak makale içeriğini her zamanki gibi kaydırabilir. İşaretlemede belirtildiği gibi, ücretsiz içeriktir.
Sekmeleri düzenlemek için aşağıdaki işaretlemeyi kullandım:
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
<a>
ve <article>
öğeleri arasında href
ve id
mülkleri ile aşağıdaki gibi bağlantılar oluşturabilirim:
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
Ardından makaleleri farklı uzunluklarda Lorem ipsum metinleriyle, bağlantıları ise farklı uzunluklarda ve resimlerle doldurdum. İçerik hazır olduğunda düzene başlayabiliriz.
Kaydırma düzenleri
Bu bileşende 3 farklı kaydırma alanı türü vardır:
- Gezinme (pembe) yatay olarak kaydırılabilir
- İçerik alanı (mavi) yatay olarak kaydırılabilir.
- Her makale öğesi (yeşil) dikey olarak kaydırılabilir.
Kaydırmayla ilgili 2 farklı öğe türü vardır:
- Pencere
overflow
mülk stilini içeren, tanımlanmış boyutlara sahip bir kutu. - Aşırı büyük yüzey
Bu düzende liste kapsayıcıları kullanılır: gezinme bağlantıları, bölüm makaleleri ve makale içerikleri.
<snap-tabs>
düzeni
Seçtiğim üst düzey düzen esnek (Flexbox) idi. Yönü column
olarak ayarladım. Böylece başlık ve bölüm dikey olarak sıralanır. Bu, ilk kaydırma penceremizdir ve taşma gizli olarak her şeyi gizler. Başlık ve bölüm, yakında ayrı bölgeler olarak kaydırma üstü özelliğini kullanacak.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
Renkli 3 kaydırma şemasına dönelim:
<header>
artık (pembe) kaydırma kapsayıcısı olmaya hazırdır.<section>
, (mavi) kaydırma kapsayıcısı olmaya hazırdır.
Aşağıda VisBug ile vurguladığım çerçeveler, kaydırma kapsayıcılarının oluşturduğu pencereleri görmemize yardımcı olur.
Sekmelerin <header>
düzeni
Sonraki düzen neredeyse aynı: Dikey sıralama oluşturmak için flex kullanıyorum.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
, bağlantı grubuyla birlikte yatay olarak hareket etmelidir ve bu başlık düzeni bu aşamayı belirlemeye yardımcı olur. Burada mutlak konumlandırılmış öğe yok.
Ardından kaydırma stilleri. Kaydırma stillerini 2 yatay kaydırma alanımız (başlık ve bölüm) arasında paylaşabileceğimizi fark ettik. Bu nedenle, .scroll-snap-x
adlı bir yardımcı program sınıfı oluşturdum.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
Her birinin x ekseninde taşma, aşırı kaydırmayı önlemek için kaydırma sınırı, dokunmatik cihazlar için gizli kaydırma çubukları ve son olarak içerik sunum alanlarını kilitlemek için kaydırma sabitleme özelliğine ihtiyacı vardır. Klavye sekme sıramız erişilebilirdir ve tüm etkileşimler, odağın doğal olarak yönlendirilmesini sağlar. Kaydırma anlık görüntü kapsayıcıları, klavyeden bant stilinde güzel bir etkileşim de alır.
Sekme başlığı <nav>
düzeni
Gezinme bağlantıları, satır sonu olmadan bir satırda dikey olarak ortalanmalıdır ve her bağlantı öğesi, kaydırma anında sabitlenen kapsayıcıya sabitlenmelidir. 2021 CSS için Swiftwork
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
Her bağlantı kendi stilini ve boyutunu belirler. Bu nedenle, gezinme düzeninin yalnızca yönü ve akışı belirtmesi gerekir. Gezinme öğelerindeki benzersiz genişlikler, göstergenin genişliğini yeni hedefe göre ayarladığı için sekmeler arasındaki geçişi eğlenceli hale getirir. Buradaki öğe sayısına bağlı olarak tarayıcı kaydırma çubuğu oluşturur veya oluşturmaz.
Sekmelerin <section>
düzeni
Bu bölüm esnek bir öğedir ve en fazla alanı kullanması gerekir. Ayrıca, makalelerin yerleştirileceği makaleler için sütunlar oluşturması gerekir. CSS 2021 için yine hızlı bir çalışma oldu. block-size: 100%
, bu öğeyi üst öğeyi mümkün olduğunca dolduracak şekilde uzatır. Ardından, kendi düzeni için üst öğenin genişliğinde 100%
oranında bir sütun dizisi oluşturur. Üst öğe için güçlü kısıtlamalar yazdığımızdan yüzdeler burada çok işe yarar.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
Bu, "dikey olarak mümkün olduğunca genişletin, itici bir şekilde" demiş gibidir (flex-shrink: 0
olarak ayarladığımız başlığı hatırlayın: Bu genişleme itişine karşı bir savunmadır). Bu, tam yükseklikteki sütunlar için satır yüksekliğini ayarlar. auto-flow
stili, ızgaraya alt öğeleri her zaman yatay bir çizgide yerleştirmesini söyler. Üst öğe penceresinin taşması için tam olarak istediğimiz şey budur.
Bazen bu konuları anlamak zor oluyor. Bu bölüm öğesi bir kutuya sığıyor ancak bir dizi kutu da oluşturdu. Görsellerin ve açıklamaların işinize yarayacağını umuyorum.
Sekmeler <article>
düzeni
Kullanıcı, makale içeriğini kaydırabilmelidir ve kaydırma çubukları yalnızca taşma varsa gösterilmelidir. Bu makale öğeleri düzgün bir şekilde yerleştirilmiş. Aynı anda kaydırma üst öğesi ve kaydırma alt öğesidir. Tarayıcı, burada bizim için bazı zor dokunma, fare ve klavye etkileşimlerini gerçekten yönetiyor.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
Makalelerin, üst kaydırma çubuğuna sığdırılmasını seçtim. Gezinme bağlantısı öğelerinin ve makale öğelerinin, ilgili kaydırma kapsayıcılarının satır içi başlangıcına nasıl sabitlendiğini gerçekten beğendim. Bu, uyumlu bir ilişki gibi görünüyor ve hissediliyor.
Makale, bir ızgara alt öğesidir ve boyutu, kaydırma kullanıcı deneyimi sunmak istediğimiz ekran alanı olacak şekilde önceden belirlenir. Yani burada herhangi bir yükseklik veya genişlik stili kullanmam gerekmiyor. Yalnızca taşmanın nasıl olacağını tanımlamam gerekiyor. overflow-y özelliğini otomatik olarak ayarladım ve ardından kaydırma etkileşimlerini kullanışlı overscroll-behavior özelliğiyle de yakaladım.
3 kaydırma alanı özeti
Aşağıda, sistem ayarlarımda "Kaydırma çubuklarını her zaman göster" seçeneğini belirledim. Bu ayarın açıkken düzenin çalışmasının, düzeni ve kaydırma orkestrasyonunu incelemem açısından iki kat daha önemli olduğunu düşünüyorum.
Bu bileşende kaydırma çubuğu oluğunu görmenin, kaydırma alanlarının nerede olduğunu, destekledikleri yönü ve birbirleriyle nasıl etkileşimde bulunduklarını açıkça göstermeye yardımcı olduğunu düşünüyorum. Bu kaydırma penceresi çerçevelerinin her birinin aynı zamanda bir düzene nasıl esneme veya kılavuz çizgisi eklediğini düşünün.
Geliştirici Araçları, aşağıdakileri görselleştirmemize yardımcı olabilir:
Kaydırma düzenleri tamamlandı: sabitleme, derin bağlantı oluşturma ve klavye erişimi. Kullanıcı deneyimi iyileştirmeleri, stil ve keyif için güçlü bir temel.
Öne çıkan özellik
Kaydırmayla sabitlenen alt öğeler, yeniden boyutlandırma sırasında kilitli konumlarını korur. Bu, cihaz döndürüldüğünde veya tarayıcı yeniden boyutlandırıldığında JavaScript'in hiçbir şeyi görüntülemesi gerekmediği anlamına gelir. Chromium Geliştirici Araçları'nda Uyumlu dışında bir mod seçip cihaz çerçevesini yeniden boyutlandırarak Cihaz Modu'nda deneyin. Öğenin, içeriğiyle birlikte görüntüde kaldığını ve kilitli olduğunu fark edin. Bu özellik, Chromium'un uygulamasını spesifikasyonla eşleşecek şekilde güncellemesinden bu yana kullanılabilir. Bu konuyla ilgili blog yayınını inceleyebilirsiniz.
Animasyon
Buradaki animasyon çalışmasının amacı, etkileşimleri kullanıcı arayüzü geri bildirimiyle net bir şekilde bağlamaktır. Bu sayede kullanıcıya, tüm içerikleri sorunsuz bir şekilde keşfetmesi için yol gösterebilir veya yardımcı olabilirsiniz. Hareketi amaca yönelik ve koşullu olarak ekleyeceğim. Kullanıcılar artık hareket tercihlerini işletim sistemlerinde belirtebiliyor. Ben de arayüzlerimde kullanıcıların tercihlerine yanıt vermekten keyif alıyorum.
Sekme alt çizgisini makalenin kaydırma konumuyla bağlayacağım. Snap, yalnızca güzel bir hizalama değil, aynı zamanda animasyonun başlangıç ve bitiş noktasını sabitlemedir.
Bu sayede, mini harita gibi çalışan <nav>
içeriğe bağlı kalır.
Kullanıcının hareket tercihini hem CSS hem de JS'den kontrol edeceğiz. Dikkatli olmanız gereken birkaç yer vardır.
Kaydırma davranışı
Hem :target
hem de element.scrollIntoView()
'un hareket davranışını iyileştirme fırsatı var. Varsayılan olarak anındadır. Tarayıcı yalnızca kaydırma konumunu belirler. Peki, orada yanıp sönmek yerine ekranı kaydırarak o konuma geçmek istersek ne olur?
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
Burada hareketi ve kullanıcının kontrol etmediği hareketi (ör. kaydırma) tanıttığımız için bu stili yalnızca kullanıcının işletim sisteminde hareket azaltma konusunda tercihi yoksa uygularız. Bu sayede, kaydırma hareketini yalnızca buna izin veren kullanıcılara sunarız.
Sekme göstergesi
Bu animasyonun amacı, göstergeyi içeriğin durumuyla ilişkilendirmenize yardımcı olmaktır. Azaltılmış hareketi tercih eden kullanıcılar için renk geçişi border-bottom
stilleri, hareketi sorun etmeyen kullanıcılar için ise kaydırma bağlantılı kaydırma + renk geçişi animasyonu kullanmaya karar verdim.
Chromium Devtools'ta tercihi değiştirebilir ve 2 farklı geçiş stilini gösterebilirim. Bunu yaparken çok eğlendim.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
Artık ihtiyaç duymadığımdan, kullanıcı azaltılmış hareketi tercih ettiğinde .snap-indicator
öğesini gizlerim. Ardından, border-block-end
stilleriyle ve bir transition
ile değiştiriyorum. Ayrıca, sekme etkileşiminde etkin gezinme öğesinde yalnızca marka alt çizgisi vurgulaması değil, metin renginin de daha koyu olduğunu fark edeceksiniz. Etkin öğenin metin rengi kontrastı daha yüksektir ve parlak bir alt ışık vurgusu vardır.
Yalnızca birkaç ekstra CSS satırı, kullanıcıların kendilerini fark edilmiş hissetmesini sağlar (hareket tercihlerine özenle saygı duyduğumuz anlamına gelir). Çok beğendim.
@scroll-timeline
Yukarıdaki bölümde, azaltılmış hareket çapraz geçiş stillerimi nasıl işlediğimi gösterdim ve bu bölümde gösterge ile kaydırma alanını nasıl bağladığımı göstereceğim. Şimdi deneysel ve eğlenceli bir içerikle karşınızdayız. Umarım siz de benim kadar heyecanlısınızdır.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
Öncelikle JavaScript'ten kullanıcının hareket tercihini kontrol ederim. Bunun sonucunda false
daha az hareketi tercih ediyorsa (kullanıcı daha az hareketi tercih ediyorsa) kaydırma bağlama hareket efektlerini uygulamayız.
if (motionOK) {
// motion based animation code
}
Bu makale yazılırken @scroll-timeline
için tarayıcı desteği yoktu. Bu, yalnızca deneysel uygulamaları içeren bir taslak spesifikasyondur. Ancak bu demoda kullandığım bir polyfill'i vardır.
ScrollTimeline
Hem CSS hem de JavaScript kaydırma zaman çizelgeleri oluşturabilse de, animasyonda canlı öğe ölçümlerini kullanabilmek için JavaScript'i etkinleştirdim.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
Bir öğenin başka bir öğenin kaydırma konumunu takip etmesini istiyorum. ScrollTimeline
oluşturarak kaydırma bağlantısının sürücüsünü (scrollSource
) tanımlarım.
Normalde web'deki animasyonlar, genel zaman aralığı tıklamasına göre çalışır. Ancak bellekte özel bir sectionScrollTimeline
kullanarak tüm bunları değiştirebilirim.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
Animasyonun animasyon karelerine geçmeden önce, kaydırma takipçisinin (tabindicator
) özel bir zaman çizelgesi (bölümümüzün kaydırma) temel alınarak animasyona tabi tutulacağını belirtmek isterim. Bu işlemle bağlantı tamamlanır ancak animasyon için aralarında geçiş yapılacak durum bilgisine sahip noktalar (anahtar kareler olarak da bilinir) eksiktir.
Dinamik animasyon kareleri
@scroll-timeline
ile animasyon yapmanın çok güçlü ve salt bildirim temelli bir CSS
yolu var, ancak yaptığım animasyon çok dinamikti. auto
genişliği arasında geçiş yapmanın ve çocukların uzunluğuna göre dinamik olarak bir dizi ana kare oluşturmanın bir yolu yoktur.
Ancak JavaScript bu bilgileri nasıl alacağını bilir. Bu nedenle, çocukları kendimiz iterasyon yaparak ve hesaplanan değerleri çalışma zamanında yakalayarak işlem yapacağız:
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
Her tabnavitem
için offsetLeft
konumunu yapılandırın ve translateX
değeri olarak kullanan bir dize döndürün. Bu işlem, animasyon için 4 dönüştürme animasyon karesi oluşturur. Genişlik için de aynı işlem yapılır. Her bir öğenin dinamik genişliği sorulur ve ardından bu değer bir anahtar kare değeri olarak kullanılır.
Yazı tiplerime ve tarayıcı tercihlerime göre örnek çıkışı aşağıda bulabilirsiniz:
TranslationX Animasyon Kareleri:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
Genişlik animasyon kareleri:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
Stratejiyi özetlemek gerekirse sekme göstergesi artık bölüm kaydırma çubuğunun kaydırma anlık görüntüleme konumuna bağlı olarak 4 animasyon karesi boyunca animasyonlu olarak gösterilecek. Sabitleme noktaları, animasyon karelerimiz arasında net bir ayrım oluşturur ve animasyonun senkronize hissini artırır.
Kullanıcı, etkileşimiyle animasyonu yönlendirir. İşaretçinin genişliği ve konumu bir bölümden diğerine değişir ve kaydırmayla mükemmel bir şekilde izlenir.
Fark etmemiş olabilirsiniz, ancak vurgulanan gezinme öğesi seçildiğinde renk geçişinden gurur duyuyorum.
Vurgulanan öğenin kontrastı daha yüksek olduğunda, seçilmemiş açık gri daha da geride görünür. Metin renginin, fareyle üzerine gelindiğinde ve seçildiğinde olduğu gibi dönüştürülmesi yaygın bir uygulamadır. Ancak kaydırma sırasında bu rengin geçişi, alt çizgi göstergesiyle senkronize edilir.
Bunu nasıl yaptığımı aşağıda görebilirsiniz:
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
Her sekme gezinme bağlantısı için, alt çizgi göstergesiyle aynı kaydırma zaman çizelgesini izleyen bu yeni renk animasyonuna ihtiyaç vardır. Öncekiyle aynı zaman çizelgesini kullanıyorum: Yöneticinin rolü kaydırma sırasında onay işareti yayınlamak olduğu için bu onay işaretini istediğimiz her tür animasyonda kullanabiliriz. Daha önce yaptığım gibi, döngüde 4 animasyon karesi oluşturup renkleri döndürüyorum.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
var(--text-active-color)
renkli animasyon karesi bağlantıyı vurgular ve diğer durumlarda standart bir metin rengidir. Dış döngü, her bir gezinme öğesi ve iç döngü, her bir gezinme öğesinin kişisel animasyon kareleri olduğundan, buradaki iç içe yerleştirilmiş döngü nispeten daha basittir. Dış döngü öğesinin iç döngü öğesiyle aynı olup olmadığını kontrol eder ve ne zaman seçildiğini öğrenmek için bunu kullanırım.
Bunu yazarken çok eğlendim. Evet.
Daha da fazla JavaScript geliştirmesi
Size burada gösterdiğim temel şeyin JavaScript olmadan çalıştığını hatırlatmakta fayda var. Bununla birlikte, JS kullanıma sunulduğunda bunu nasıl iyileştirebileceğimize bakalım.
Derin bağlantılar
Derin bağlantılar daha çok mobil bir terimdir ancak derin bağlantının amacının, bir URL'yi doğrudan bir sekmenin içeriğiyle paylaşabilmeniz için sekmelerle ilgili olduğunu düşünüyorum. Tarayıcı, sayfa içinde URL karmasıyla eşleşen kimliğe gider. Bu onload
işleyicinin, platformlar genelinde etki yarattığını tespit ettim.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
Kaydırma sonu senkronizasyonu
Kullanıcılarımız her zaman tıklama veya klavye kullanmaz. Bazen, yapabilmeleri gerektiği gibi, ekranı serbestçe kaydırırlar. Bölüm kaydırma çubuğu kaymayı durdurduğunda, kaydırma çubuğunun durduğu yerin üst gezinme çubuğunda eşleşmesi gerekir.
Kaydırma işleminin sona ermesini şu şekilde beklerim:
js
tabsection.addEventListener('scroll', () => {
clearTimeout(tabsection.scrollEndTimer);
tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100);
});
Bölümler kaydırıldığında, varsa bölüm zaman aşımını temizleyin ve yeni bir zaman aşımı başlatın. Bölümler kaydırma durduğunda zaman aşımını temizlemeyin ve dinlenmeden 100 ms sonra etkinleşin. Tetiklendiğinde, kullanıcının nerede durduğunu bulmaya çalışan işlevi çağırın.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
Kaydırma sabitlendiyse geçerli kaydırma konumunun kaydırma alanının genişliğiyle bölünmesi ondalık basamak yerine tam sayı sonucu verir. Ardından, bu hesaplanmış dizin aracılığıyla önbelleğimizde bir navitem öğesi yakalamaya çalışıyorum. Bir şey bulursa eşleşmeyi etkinleştirilecek şekilde gönderiyorum.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
Etkin sekme ayarlanırken, önce etkin olan sekme temizlenir, ardından gelen gezinme öğesine etkin durum özelliği verilir. scrollIntoView()
çağrısında, CSS ile eğlenceli bir etkileşim vardır.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
Yatay kaydırma tutturma yardımcı programı CSS'sinde, kullanıcı harekete dayanıklıysa smooth
kaydırma uygulayan bir medya sorgusu iç içe yerleştirdik. JavaScript, öğeleri görüntüye almak için özgürce çağrı yapabilir ve CSS, kullanıcı deneyimini açık bir şekilde yönetebilir.
Bazen çok hoş bir çift oluyorlar.
Sonuç
Bunu nasıl yaptığımı öğrendiğinize göre, siz ne yapardınız? Bu da biraz eğlenceli bileşen mimarisi oluşturur! En sevdikleri çerçevede slot içeren ilk sürümü kim yapacak? 🙂
Yaklaşımlarımızı çeşitlendirelim ve web'de uygulama geliştirmenin tüm yollarını öğrenelim. Bir Glitch oluşturun, benimle tweet'de paylaşın. Topluluk remiksleri bölümüne ekleyeceğim.
Topluluk remiksleri
- @devnook, @rob_dodson ve @DasSurma ile Web Bileşenleri: article.
- @jhvanderschee düğmeleri ile: Codepen.