Sekmeler bileşeni oluşturma

iOS ve Android uygulamalarında bulunan sekmelere benzer bir sekme bileşeninin nasıl oluşturulacağına dair temel bilgiler içerir.

Bu yayında, web için duyarlı, birden fazla cihaz girişini destekleyen ve tarayıcılarda çalışan bir Sekmeler bileşeni oluşturma konusunda düşüncelerimizi paylaşmak istiyorum. Demoyu deneyin.

Tanıtım

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 şekilde ve biçimde olabilir. Öncelikle <frame> öğesine dayalı masaüstü sekmeleri vardı ve şimdi, fizik özelliklerine dayalı olarak içerik canlandıran tereyağlı mobil bileşenlerimiz var. Hepsi aynı şeyi yapmaya çalışıyor: alandan tasarruf etmek.

Günümüzde, sekmeler kullanıcı deneyiminin olmazsa olmazları, içeriklerin ekran çerçevesi içindeki görünürlüğünü değiştiren düğmeyle 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&#39;in bileşen konseptine uyguladığı stil çeşitliliği nedeniyle oldukça kaotik.
Son 10 yıla ait sekme bileşeni web tasarımı stillerinden oluşan bir kolaj

Web Taktikleri

Sonuçta, çok önemli birkaç web platformu özelliği sayesinde bu bileşeni oluşturmayı oldukça kolay buldum:

  • Uygun kaydırma durdurma konumları ile şık kaydırma ve klavye etkileşimleri için scroll-snap-points
  • Tarayıcı için URL karmaları aracılığıyla kullanılan derin bağlantılar sayfa içi kaydırma sabitleme ve paylaşım desteği
  • <a> ve id="#hash" öğe işaretlemesiyle ekran okuyucu desteği
  • Çapraz geçiş geçişlerini ve anında sayfa içi kaydırmayı etkinleştirmek için prefers-reduced-motion
  • Seçilen sekmenin dinamik olarak altını çizmek ve renk değişikliği yapmak için taslak içi @scroll-timeline web özelliği

HTML

Temel olarak kullanıcı deneyimi şu şekildedir: Bir bağlantıyı tıklayın, URL'nin iç içe yerleştirilmiş sayfa durumunu temsil etmesini sağlayın ve tarayıcı eşleşen öğeye doğru kaydırdıkça içerik alanının güncellendiğini görürsünüz.

Yapısal içerik üyeleri de var: bağlantılar ve :target. Elimizde <nav> özelliğinin mükemmel olduğu bir bağlantı listesine ve <section> öğesinin mükemmel olduğu <article> öğelerinin bir listesine ihtiyacımız vardır. Her bağlantı karması bir bölümle eşleşir ve tarayıcının sabitleme aracılığıyla öğeleri kaydırmasına izin verir.

Odaklanılan içeriğin içine kayan bir bağlantı düğmesi tıklanır

Örneğin, bir bağlantının tıklanması, Chrome 89'da :target makalesinin otomatik olarak odaklanmasını sağlar. JS gerekli değildir. Kullanıcı daha sonra her zamanki gibi giriş cihazıyla makale içeriğini kaydırabilir. İşaretlemede belirtildiği gibi bu ü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 özellikleriyle 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>

Daha sonra makaleleri karışık miktarda lorem ile, bağlantıları da karışık uzunluk ve resim başlık grubuyla doldurdum. Üzerinde çalışacağımız içerikle, düzeni başlatmaya başlayabiliriz.

Kayan düzenler

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ırma alanlarını ana hatlarıyla belirten ve hangi yönün kaydırılacağını gösteren, renk eşlemeli yön oklarının bulunduğu 3 renkli kutu.

Kaydırmayla ilgili 2 farklı öğe türü vardır:

  1. Pencere
    overflow özellik stiline sahip tanımlı boyutlara sahip bir kutu.
  2. Aşırı büyük bir yüzey
    Bu düzende liste kapsayıcılarıdı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ıralanmış. Bu, ilk kaydırma penceremizdir ve taşma işlevi gizlenmiş her şeyi gizler. Başlık ve bölüm, yakında ayrı alt bölgeler olarak fazladan kaydırmayı kullanacaktır.

HTML
<snap-tabs>
  <header></header>
  <section></section>
</snap-tabs>
CSS
  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 against 
needing 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }

Renkli 3 kaydırma şemasına dönelim:

  • <header> artık (pink) kaydırma kapsayıcısı olmaya hazır.
  • <section>, (mavi) kaydırma kapsayıcısı için 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.

başlık ve bölüm öğelerinin üzerinde, bileşen içinde kapladıkları alanı gösteren hotpink yer paylaşımları bulunur.

Sekmeler <header> düzeni

Sonraki düzen neredeyse aynıdır: Dikey sıralama oluşturmak için flex özelliğini kullanıyorum.

HTML
<snap-tabs>
  <header>
    <nav></nav>
    <span class="snap-indicator"></span>
  </header>
  <section></section>
</snap-tabs>
CSS
header {
  display: flex;
  flex-direction: column;
}

.snap-indicator, bağlantı grubuyla yatay olarak hareket etmelidir ve bu başlık düzeni sahnenin ayarlanmasına yardımcı olur. Burada mutlak konumlandırılmış öğe yok!

nav ve span.indicator öğelerinin üzerinde, bileşende kapladıkları alanı özetleyen hotpink yer paylaşımları bulunur

Sonra, kaydırma stilleri. Kaydırma stillerini 2 yatay kaydırma alanımız (başlık ve bölüm) arasında paylaşabileceğimiz ortaya çıktı. Ben de bir yardımcı sınıf (.scroll-snap-x) yaptım.

.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, fazla kaydırmayı yakalamak için kaydırma çubuğu, dokunmatik cihazlar için gizli kaydırma çubukları ve son olarak içerik sunum alanlarını kilitlemek için kaydırma çubuğunun olması gerekir. Klavye sekme sıramıza erişilebiliyor ve etkileşimler doğal bir şekilde odaklanmaya odaklanıyor. Kaydırma tutturma kapsayıcıları, klavyelerinden atlı karınca stilinde güzel bir etkileşim de elde eder.

Sekme başlığı <nav> düzeni

Gezinme bağlantılarının bir satır içine, satır sonu olmadan, dikey olarak ortalanmış şekilde yerleştirilmesi ve her bir bağlantı öğesi, kaydırma tutturma kapsayıcısına tutturulmalıdır. Swift, 2021 CSS için çalıştı!

HTML
<nav>
  <a></a>
  <a></a>
  <a></a>
  <a></a>
</nav>
CSS
  nav {
  display: flex;

  & a {
    scroll-snap-align: start;

    display: inline-flex;
    align-items: center;
    white-space: nowrap;
  }
}

Her bağlantı stili ve kendisinin boyutu olduğundan gezinme düzeninin yalnızca yönü ve akışı belirtmesi gerekir. Gezinme öğelerinin benzersiz genişlikleri, gösterge genişliğini yeni hedefe göre ayarlarken sekmeler arasındaki geçişi eğlenceli hale getirir. Burada kaç öğe olduğuna bağlı olarak tarayıcı bir kaydırma çubuğu oluşturur veya oluşturmaz.

gezinme öğelerinin üzerinde, bileşen içinde kapladıkları alanı ve nereye taştıklarını gösteren hotpink yer paylaşımları bulunur.

Sekmeler <section> düzeni

Bu bölüm, esnek bir öğedir ve alanın baskın tüketicisi olmalıdır. Ayrıca, makalelerin yerleştirileceği sütunlar oluşturması gerekir. Yine CSS 2021 için hızlı bir şekilde çalışın. block-size: 100%, bu öğeyi üst öğeyi mümkün olduğunca dolduracak şekilde genişletir. Daha sonra, kendi düzeni için üst öğenin genişliği 100% olan bir sütun serisi oluşturur. Burada yüzdeler çok işe yarıyor, çünkü ana yayıncıyla ilgili güçlü kısıtlamalar yazdık.

HTML
<section>
  <article></article>
  <article></article>
  <article></article>
  <article></article>
</section>
CSS
  section {
  block-size: 100%;

  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
}

Tam yükseklikte bir grup sütun için satır yüksekliğini ayarlayan "bu genişletme aktarmaya karşı bir savunmadır" ifadesiyle "mümkün olduğunca dikey olarak, ısrarla genişlet" diyoruz (flex-shrink: 0 olarak ayarladığımız başlığı unutmayın). auto-flow stili, ızgaraya alt öğeleri her zaman yatay bir çizgide, sarmalama yapmadan, tam olarak istediğimiz şekilde yerleştirmesini ve üst pencereden taşacak şekilde yerleştirmesini söyler.

makale öğelerinin üzerinde, bileşen içinde kapladıkları alanı ve nereye taştıklarını gösteren hotpink yer paylaşımları bulunur.

Bazen kafamı çevirmekte zorlanıyorum. Bu bölüm öğesi bir kutuya sığıyor, ancak aynı zamanda bir dizi kutu da oluşturmuş. Görsellerin ve açıklamaların yardımcı olduğunu umuyorum.

Sekmeler <article> düzeni

Kullanıcı, makale içeriğini kaydırabilmelidir ve kaydırma çubukları yalnızca taşma olduğunda görünmelidir. Bu makale öğeleri düzgün bir konumdadır. Bunlar aynı anda, kaydırma üst ve kaydırma alt öğesidir. Tarayıcı, burada bizim için bazı zorlu dokunma, fare ve klavye etkileşimlerini gerçekten işliyor.

HTML
<article>
  <h2></h2>
  <p></p>
  <p></p>
  <h2></h2>
  <p></p>
  <p></p>
  ...
</article>
CSS
article {
  scroll-snap-align: start;

  overflow-y: auto;
  overscroll-behavior-y: contain;
}

Makalelerin, üst kaydırıcıya tutturulmasını tercih ettim. Gezinme bağlantısı öğelerinin ve makale öğelerinin, ilgili kaydırma kapsayıcılarının satır içi başlangıcına tutturulmasını çok seviyorum. Uyumlu bir ilişki gibi görünür ve hissedilir.

makale öğesinin ve alt öğelerinin üzerinde hotpink yer paylaşımları var. Bu yer paylaşımları, bileşende kapladıkları alanı ve taştıkları yönü özetliyor

Makale, ızgara alt öğesidir ve boyutu, kaydırma kullanıcı deneyimi sağlamak istediğimiz görüntü alanı olarak önceden belirlenir. Yani, burada herhangi bir yüksekliğe veya genişlik stiline ihtiyacım yok, sadece nasıl taşacağını tanımlamam gerekiyor. Taşma-y ayarını otomatik olarak yapıyorum ve ardından kaydırma etkileşimlerini, kullanışlı "fazla kaydırma davranışı" özelliğiyle yakalıyorum.

3 kaydırma alanı özeti

Sistem ayarlarımda aşağıda "kaydırma çubuklarını her zaman göster" seçeneğini belirledim. Düzeni ve kaydırma düzenini incelemem gerektiğinden, düzenin bu ayar etkinken çalışması iki kat önemli.

3 kaydırma çubuğu gösterilecek şekilde ayarlandı. Bu çubuk artık düzen alanında yer kaplıyor ve bileşenimiz hâlâ harika görünüyor

Bence bu bileşendeki kaydırma çubuğu oluğunu görmek, kaydırma alanlarının nerede olduğunu, destekledikleri yönün ve birbirleriyle nasıl etkileşim kurduklarını açıkça göstermeye yardımcı oluyor. Bu kaydırma penceresi çerçevelerinin her birinin aynı zamanda bir düzenin esnek veya ızgara üst öğesi olduğunu düşünün.

Geliştirici Araçları, aşağıdakileri görselleştirmemize yardımcı olabilir:

kaydırma alanlarında ızgara ve flexbox aracı yer paylaşımları bulunuyor. Bileşenin içinde kapladıkları alan ve bu yüzeylerin taşma yönü gösteriliyor.
Bağlantı öğeleri ile dolu flexbox nav öğesi düzenini, makale öğeleriyle dolu ızgara bölüm düzenini ve bir paragrafla ve bir başlık öğesiyle dolu makale öğelerini gösteren Chromium Geliştirici Araçları.

Kaydırma düzenleri tamdır: yapışma, derin bağlantı oluşturma ve klavyeden erişilebilir. Kullanıcı deneyimi iyileştirmeleri, stil ve memnuniyet için sağlam bir temel.

Öne çıkan özellik

Kaydırarak tutturulan alt öğeler, yeniden boyutlandırma sırasında kilitli konumlarını korur. Diğer bir deyişle, cihaz döndürme veya tarayıcı yeniden boyutlandırmada JavaScript'in herhangi bir şey görüntülemesi gerekmez. Bu özelliği Chromium Geliştirici Araçları Cihaz Modu'nda deneyin. Bunun için Duyarlı dışında bir mod seçip cihaz çerçevesini yeniden boyutlandırın. Öğenin görünümde kaldığına ve içeriğiyle kilitlendiğine dikkat edin. Bu özellik, Chromium uygulamasını spesifikasyonla eşleşecek şekilde güncellediğinden beri kullanılabilir. Bu konuyla ilgili blog yayınını burada bulabilirsiniz.

Animasyonlar

Buradaki animasyon çalışmasının amacı, etkileşimleri kullanıcı arayüzü geri bildirimiyle açık bir şekilde bağlamaktır. Bu, kullanıcının tüm içeriği sorunsuz bir şekilde keşfetmesine yardımcı olur. Belirli bir amaçla ve koşula olarak hareket ekliyorum. Kullanıcılar artık hareket tercihlerini işletim sistemlerinde belirtebiliyor ve arayüzlerimde tercihlerini yanıtlamaktan büyük keyif alıyorum.

Makale kaydırma konumuna bir sekme alt çizgisi bağlayacağım. Yapıştırma sadece uygun bir hizalama değil, aynı zamanda bir animasyonun başlangıcını ve sonunu da sabitler. Bu şekilde, mini harita işlevi gören <nav>, içeriğe bağlı kalır. Kullanıcının hareket tercihini hem CSS hem de JS'den kontrol edeceğiz. Dikkate alınması gereken birkaç harika yer var.

Kaydırma davranışı

Hem :target hem de element.scrollIntoView() uygulamasının hareket davranışını iyileştirme fırsatı bulunmaktadır. Varsayılan olarak anında çalışır. Tarayıcı yalnızca kaydırma konumunu ayarlar. Orada yanıp sönmek yerine o kaydırma konumuna geçiş yapmak istersek ne olur?

@media (prefers-reduced-motion: no-preference) {
  .scroll-snap-x {
    scroll-behavior: smooth;
  }
}

Burada hareket ve kullanıcının kontrol edemediği hareket (kaydırma gibi) uygulamaya başladığımızdan, bu stili yalnızca kullanıcının işletim sisteminde azaltılmış hareketle ilgili bir tercihi yoksa uyguluyoruz. Bu şekilde, kaydırma hareketini yalnızca bu konuda memnun olan kişiler için tanıtırız.

Sekme göstergesi

Bu animasyonun amacı, göstergeyi içeriğin durumuyla ilişkilendirmeye yardımcı olmaktır. Daha az hareket etmeyi tercih eden kullanıcılar için border-bottom stillerinin renk geçişine, harekete geçmeyen kullanıcılar için kaydırma bağlantılı kaydırmalı ve rengi soldurma animasyonu uygulamaya karar verdim.

Chromium Geliştirici Araçları'nda tercihi açıp kapatabilir ve 2 farklı geçiş stilini gösterebilirim. Bunu hazırlarken ç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;
  }
}

Kullanıcılar artık ihtiyacım kalmadığı için azalan hareketi tercih ettiğinde .snap-indicator etiketini saklıyorum. Daha sonra, bunu border-block-end stilleri ve transition ile değiştiriyorum. Ayrıca, sekmeler etkileşiminde, etkin gezinme öğesinin yalnızca bir marka altı çizili vurgusu olmadığını, metin renginin daha koyu da olduğuna dikkat edin. Etkin öğe daha yüksek metin rengi kontrastına ve parlak bir alt ışık vurgusuna sahiptir.

Sadece birkaç satır CSS ile izleyicilerin fark edildiklerini hissetmelerini sağlayabilirsiniz (hareket tercihlerine özenli bir şekilde saygı gösterdiğimiz için). Buna bayıldım.

@scroll-timeline

Yukarıdaki bölümde, azaltılmış hareket çapraz geçişi stillerini nasıl ele aldığımı göstermiştim. Bu bölümde ise gösterge ile kaydırma alanını nasıl birbirine bağladığımı göstereceğim. Sırada eğlenceli ve deneysel bir şeyler var. Umarım siz de benim kadar heyecanlısınızdır.

const { matches:motionOK } = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
);

Önce JavaScript'ten kullanıcının hareket tercihini kontrol ediyorum. Bunun sonucunda false (kullanıcının daha az hareket tercih ettiği anlamına gelir) kaydırma bağlantı hareketi efektlerinin hiçbirini çalıştırmayız.

if (motionOK) {
  // motion based animation code
}

Bu makalenin yazıldığı tarihte @scroll-timeline için tarayıcı desteği mevcut değildir. Yalnızca deneysel uygulamaları olan bir taslak spesifikasyondur. Yine de bu demoda kullandığım bir çoklu dolgusu var.

ScrollTimeline

Hem CSS hem de JavaScript kaydırma zaman çizelgeleri oluşturabiliyor olsa da 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
});

1 öğenin başka bir öğenin kaydırma konumunu takip etmesini istiyorum ve bir ScrollTimeline oluşturarak kaydırma bağlantısı sürücüsünü (scrollSource) tanımlıyorum. Normalde web'deki bir animasyon genel bir zaman aralığı onayına karşı çalışır, ancak bellekte özel bir sectionScrollTimeline ile bunların tümünü değiştirebilirim.

tabindicator.animate({
    transform: ...,
    width: ...,
  }, {
    duration: 1000,
    fill: 'both',
    timeline: sectionScrollTimeline,
  }
);

Animasyonun animasyon karelerine girmeden önce, kaydırmanın takipçisine (tabindicator) özel bir zaman çizelgesine, yani bölümümüzün kaydırıldığı yere göre animasyon uygulanacağını belirtmenin önemli olduğunu düşünüyorum. Bu işlem, bağlantıyı tamamlar ancak animasyon kareleri olarak da bilinen son bileşen olan durum bilgili noktalara eksik kalır.

Dinamik animasyon kareleri

@scroll-timeline ile animasyon yapmanın gerçekten basit bir bildirim temelli CSS yolu var ama seçtiğim animasyon çok dinamikti. auto genişliği arasında geçiş yapılamaz ve alt öğelerin uzunluğuna göre dinamik olarak birkaç animasyon karesi oluşturulamaz.

JavaScript, bu bilgiyi nasıl edineceğini bilir; bu yüzden alt öğeleri kendimiz tekrarlayıp, hesaplanan değerleri çalışma zamanında yakalarız:

tabindicator.animate({
    transform: [...tabnavitems].map(({offsetLeft}) =>
      `translateX(${offsetLeft}px)`),
    width: [...tabnavitems].map(({offsetWidth}) =>
      `${offsetWidth}px`)
  }, {
    duration: 1000,
    fill: 'both',
    timeline: sectionScrollTimeline,
  }
);

Her bir tabnavitem için offsetLeft konumunu yok edin ve bu konumu translateX değeri olarak kullanan bir dize döndürün. Bu işlem, animasyon için 4 dönüşüm animasyon karesi oluşturur. Aynı şey genişlik için de yapılır. Her birine dinamik genişliğinin ne olduğu sorulur ve daha sonra, bu değer bir animasyon karesi değeri olarak kullanılır.

Yazı tiplerime ve tarayıcı tercihlerime dayalı olarak örnek çıktıyı aşağıda bulabilirsiniz:

TranslateX 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 için, sekme göstergesi bölüm kaydırıcısının kaydırma tutturma konumuna bağlı olarak 4 animasyon karesinde animasyon oluşturur. Yapışma noktaları, animasyon karelerimiz arasında net bir betimleme oluşturur ve animasyonun senkronize hissine gerçekten katkıda bulunur.

etkin sekme ve etkin olmayan sekme, her ikisi için de geçiş puanlarını gösteren VisBug yer paylaşımları ile gösterilir.

Kullanıcı, etkileşimiyle animasyonu yönlendirir. Göstergenin genişliğinin ve konumunun bir bölümden diğerine geçtiğini görür ve kaydırmayla bunu mükemmel bir şekilde izler.

Fark etmemiş olabilirsiniz, ama vurgulanan gezinme öğesi seçildikçe renk geçişinden gurur duyuyorum.

Vurgulanan öğe daha fazla kontrasta sahip olduğunda, seçilmeyen açık gri renk daha da geriye itilir. Metin için renk geçişi (ör. fareyle üzerine gelindiğinde ve seçildiğinde) yaygındır, ancak alt çizgi göstergesiyle senkronize olarak kaydırma sırasında bu rengin geçişi bir sonraki düzeydir.

Bunu şu şekilde yaptım:

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ı, alt çizgi göstergesiyle aynı kaydırma zaman çizelgesini izleyen bu yeni renkli animasyona ihtiyaç duyar. Öncekiyle aynı zaman çizelgesini kullanıyorum. Görevi kaydırmada onay işareti yapmak olduğundan, bu onay işaretini istediğimiz türlerde kullanabiliriz. Daha önce yaptığım gibi, döngü içinde 4 animasyon karesi oluşturuyor ve 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) renge sahip animasyon karesi bağlantıyı vurgular. Aksi halde standart bir metin rengi olur. Dış döngü her bir nav öğesi, iç döngü ise her navitem'ın kişisel animasyon kareleri olduğundan iç içe geçmiş döngü bunu nispeten basit hale getirir. Dış döngü öğesinin iç döngüyle aynı olup olmadığını kontrol ediyorum ve ne zaman seçileceğini bilmek için bunu kullanıyorum.

Bunu yazarken çok eğlendim. Oldukça çok.

Daha fazla JavaScript geliştirmesi

Burada gösterdiklerimin temelinin JavaScript olmadan çalıştığını hatırlatmak isteriz. Bununla birlikte, JS kullanılabilir olduğunda bunu nasıl geliştirebileceğimize bakalım.

Derin bağlantılar daha çok mobil bir terimdir, ancak bence derin bağlantının amacı, bir URL'yi doğrudan bir sekmenin içeriğiyle paylaşabilmenizi sağlayan sekmelerle karşılanıyor. Tarayıcı sayfa içinde, URL karmasıyla eşleşen kimliğe gider. Bu onload işleyicinin platformlar genelinde etkili olduğunu buldum.

window.onload = () => {
  if (location.hash) {
    tabsection.scrollLeft = document
      .querySelector(location.hash)
      .offsetLeft;
  }
}

Kaydırma senkronizasyonunu sonlandır

Kullanıcılarımız her zaman tıklama yapmıyor veya klavye kullanmıyor, bazen de normalde yapabilecekleri gibi yalnızca serbest kaydırma yapıyorlar. Bölüm kaydırma çubuğu kaydırmayı durdurduğunda, indiği yerin üst gezinme çubuğunda eşleştirilmesi gerekir.

Kaydırma sonu için beklemem şu şekilde: js tabsection.addEventListener('scroll', () => { clearTimeout(tabsection.scrollEndTimer); tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100); });

Bölümler kaydırılırken, varsa bölüm zaman aşımını temizleyin ve yeni bir bölüm başlatın. Bölümlerin kaydırılması durduğunda, zaman aşımını silmeyin ve dinledikten sonra 100 ms. Tetiklendiğinde, kullanıcının nerede durduğunu bulmaya çalışan fonksiyonu çağırın.

const determineActiveTabSection = () => {
  const i = tabsection.scrollLeft / tabsection.clientWidth;
  const matchingNavItem = tabnavitems[i];

  matchingNavItem && setActiveTab(matchingNavItem);
};

Kaydırmanın yapıştığını varsayarsak, geçerli kaydırma konumunun kaydırma alanının genişliğinden böldüğümüzde ondalık değer yerine bir tam sayı olması gerekir. Daha sonra, bu hesaplanan dizin aracılığıyla önbelleğimizden bir navitem almaya çalışıyorum ve bir şey bulursa eşleşmeyi etkin olarak ayarlamak üzere gönderiyorum.

const setActiveTab = tabbtn => {
  tabnav
    .querySelector(':scope a[active]')
    .removeAttribute('active');

  tabbtn.setAttribute('active', '');
  tabbtn.scrollIntoView();
};

Etkin sekmenin ayarlanması, o sırada etkin olan herhangi bir sekmenin temizlenmesi ve ardından gelen gezinme öğesine etkin durum özelliğinin verilmesiyle başlar. scrollIntoView() çağrısı, CSS ile kayda değer bir eğlenceli etkileşim içeriyor.

.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 yapma yardımcı programı CSS'de, kullanıcı harekete izin veriyorsa smooth kaydırma uygulayan bir medya sorgusunu iç içe yerleştirdik. JavaScript, öğeleri görünüme kaydırmak için serbestçe çağrılar yapabilir ve CSS, kullanıcı deneyimini bildirimli şekilde yönetebilir. Bazen çok keyifli ve keyifli bir eşleştirme yapıyorlar.

Sonuç

Nasıl yaptığımı artık bildiğine göre sen ne yaparsın? Bu da bileşen mimarisini eğlenceli hale getirir. En sevdiği çerçevedeki slotlarla 1. sürümü kim yapacak? 🙂

Yaklaşımlarımızı çeşitlendirelim ve web'de geliştirme yapmanın tüm yollarını öğrenelim. Bir Glitch oluşturun, kendi sürümünüzü tweet'leyin, ardından bunu aşağıdaki Topluluk remiksleri bölümüne eklerim.

Topluluk remiksleri