İçerik haritası bileşeni oluşturma

Kullanıcıların sitenizde gezinmesi için duyarlı ve erişilebilir bir içerik haritası bileşeni oluşturmaya dair temel bir genel bakış.

Bu gönderide, içerik haritası bileşenlerini oluşturmanın bir yolu üzerine düşüncelerimi paylaşmak istiyorum. Demoyu deneyin.

Demo

Video kullanmayı tercih ederseniz bu gönderinin YouTube versiyonunu kullanabilirsiniz:

Genel bakış

İçerik haritası bileşeni, kullanıcının site hiyerarşisinin neresinde olduğunu gösterir. Adı, koyu ormanlarda arkalarına içerik haritası bırakan ve kırıntıları geriye doğru izleyerek eve giden yolu bulan Hansel ve Gretel'e aittir.

Bu yayındaki içerik haritaları standart içerik haritası değildir ve içerik haritasına benzer. Eşdüzey sayfaları bir <select> ile gezinmeye doğrudan yerleştirerek ek işlevler sunarak çok katmanlı erişimi mümkün kılar.

Arka plan kullanıcı deneyimi

Yukarıdaki bileşen demo videosunda yer tutucu kategoriler, video oyunu türleridir. Bu patika, aşağıda gösterildiği gibi home » rpg » indie » on sale yolunda gidilerek oluşturulur.

Bu içerik haritası bileşeni, kullanıcıların bu bilgi hiyerarşisinde hareket etmesini, dalları atlamasını ve hızlı ve doğru sayfaları seçmesini sağlamalıdır.

Bilgi mimarisi

Koleksiyonlar ve öğeler açısından düşünmeyi faydalı buluyorum.

Koleksiyonlar

Koleksiyon, aralarından seçim yapabileceğiniz bir dizi seçenektir. Bu yayının içerik haritası prototipinin ana sayfasından FPS, RYO, kavga, zindan tarayıcısı, spor ve bulmaca koleksiyonları bulunuyor.

Öğe sayısı

Video oyunu bir öğedir. Belirli bir koleksiyon, başka bir koleksiyonu temsil ediyorsa öğe de olabilir. Örneğin, RPG bir öğe ve geçerli bir koleksiyondur. Öğe olduğunda kullanıcı bu koleksiyon sayfasındadır. Örneğin, Rol Yapma Oyunları sayfasında yer alırlar. Bu sayfada AAA, Bağımsız ve Self Yayınlanan ek alt kategorileri de dahil olmak üzere RPG oyunlarının bir listesi yer alır.

Bilgisayar bilimleri terimlerinde, bu içerik haritası bileşeni çok boyutlu bir diziyi temsil eder:

const rawBreadcrumbData = {
  "FPS": {...},
  "RPG": {
    "AAA": {...},
    "indie": {
      "new": {...},
      "on sale": {...},
      "under 5": {...},
    },
    "self published": {...},
  },
  "brawler": {...},
  "dungeon crawler": {...},
  "sports": {...},
  "puzzle": {...},
}

Uygulamanız veya web siteniz farklı bir çok boyutlu dizi oluşturan özel bilgi mimarisine (IA) sahip olacaktır. Ancak koleksiyon açılış sayfaları ve hiyerarşi geçişi konseptinin de içerik haritalarına dahil edilmesini umuyorum.

Düzenler

Markup

İyi bileşenler uygun HTML ile başlar. Bu bölümde, işaretleme seçeneklerimi ve bunların genel bileşeni nasıl etkilediğinden bahsedeceğim.

Koyu ve açık şema

<meta name="color-scheme" content="dark light">

Yukarıdaki snippet'te yer alan color-scheme meta etiketi, tarayıcıya bu sayfanın açık ve koyu tarayıcı stillerini istediğini bildirir. Örnek içerik haritaları bu renk şemaları için herhangi bir CSS içermez. Bu nedenle, içerik haritaları tarayıcı tarafından sağlanan varsayılan renkleri kullanır.

<nav class="breadcrumbs" role="navigation"></nav>

Dolaylı bir ARIA gezinme rolüne sahip olan sitede gezinme için <nav> öğesinin kullanılması uygundur. Testlerde, role özelliğinin ekran okuyucunun öğeyle etkileşim kurma şeklini değiştirdiğini fark ettim ve bu özelliğin aslında gezinme olarak duyurulduğunu gördüm ve bu özelliği eklemeyi seçtim.

Simgeler

Simge bir sayfada tekrarlandığında, SVG <use> öğesi path öğesini bir kez tanımlayıp simgenin tüm örnekleri için kullanabileceğiniz anlamına gelir. Bu, aynı yol bilgilerinin tekrarlanmasını önleyerek daha büyük belgelere ve yol tutarsızlığı potansiyeline neden olur.

Bu tekniği kullanmak için sayfaya gizli bir SVG öğesi ekleyin ve simgeleri bir <symbol> öğesinin içine benzersiz bir kimlikle sarmalayın:

<svg style="display: none;">

  <symbol id="icon-home">
    <title>A home icon</title>
    <path d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
  </symbol>

  <symbol id="icon-dropdown-arrow">
    <title>A down arrow</title>
    <path d="M19 9l-7 7-7-7"/>
  </symbol>

</svg>

Tarayıcı SVG HTML'sini okur, simge bilgilerini belleğe yerleştirir ve sayfanın geri kalanında simgenin diğer kullanımları için kimliğe referans vererek devam eder. Örneğin:

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-home" />
</svg>

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-dropdown-arrow" />
</svg>

Oluşturulan bir SVG kullanım öğesini gösteren Geliştirici Araçları.

Sayfa performansı üzerindeki etkisi minimum düzeyde ve esnek stil ile, bir kez tanımlayın, istediğiniz kadar kullanın. SVG öğesine aria-hidden="true" eklendiğine dikkat edin. Simgeler, yalnızca içeriği duyan kullanıcılara göz atan kullanıcılar için kullanışlı değildir. Simgeleri bu kullanıcılardan gizleyip gereksiz sesler eklemelerini önlersiniz.

Geleneksel içerik haritası ile bu bileşendekiler burada ayrılır. Normalde bu yalnızca bir <a> bağlantısıdır ancak gizlenmiş bir seçimle geçiş kullanıcı deneyimi ekledim. .crumb sınıfı bağlantı ve simgenin yerleştirilmesinden, .crumbicon ise simge ve seçim öğesinin birlikte yerleştirilmesinden sorumludur. İşlevleri bölünmüş düğmeye çok benzediği için sayfada gezinme işlevine benzetildiği için buna bölünmüş bağlantı adını verdim.

<span class="crumb">
  <a href="#sub-collection-b">Category B</a>
  <span class="crumbicon">
    <svg>...</svg>
    <select class="disguised-select" title="Navigate to another category">
      <option>Category A</option>
      <option selected>Category B</option>
      <option>Category C</option>
    </select>
  </span>
</span>

Bir bağlantı ve bazı seçenekler özel bir şey değildir ancak basit bir içerik haritasına daha fazla işlev ekler. <select> öğesine title eklemek, ekran okuyucu kullanıcılarına düğmenin işlemi hakkında bilgi vererek fayda sağlar. Ancak diğer herkese de aynı yardımı sunduğundan iPad'in önde ve ortada yer aldığını göreceksiniz. Bir özellik, birçok kullanıcıya düğme bağlamı sağlar.

Görünmez seçim öğesinin fareyle üzerine gelindiği ve içeriğe dayalı ipucunun gösterildiği ekran görüntüsü.

Ayırıcı süslemeleri

<span class="crumb-separator" aria-hidden="true">→</span>

Ayırıcılar isteğe bağlıdır. Yalnızca bir ayırıcı eklemek de iyi sonuç verir (yukarıdaki videoda üçüncü örneğe bakın). Daha sonra, süsleme amaçlı oldukları ve ekran okuyucunun duyurması gereken bir şey olmadıkları için her aria-hidden="true" öğesini veriyorum.

Bir sonraki adımda ele alınacak olan gap özelliği, bu boşlukların basit şekilde ayarlanmasını sağlar.

Stiller

Renk, sistem renklerini kullandığından stiller için çoğunlukla boşluklar ve yığınlardan oluşur.

Düzenin yönü ve akışı

Flexbox yer paylaşımı özelliğiyle içerik haritası gezinme hizalamasını gösteren Geliştirici Araçları.

Birincil gezinme öğesi nav.breadcrumbs, alt yayıncının kullanması için kapsamlı bir özel özellik ayarlar ve yatay olarak dikey olarak hizalanan bir düzen oluşturur. Bu şekilde kırıntılar, ayırıcılar ve simgeler hizalanır.

.breadcrumbs {
  --nav-gap: 2ch;

  display: flex;
  align-items: center;
  gap: var(--nav-gap);
  padding: calc(var(--nav-gap) / 2);
}

Flexbox yer paylaşımlarıyla dikey olarak gösterilen bir içerik haritası.

Her .crumb ayrıca bir miktar boşlukla yatay olarak dikey olarak hizalanan bir düzen oluşturur ancak özel olarak bağlantı alt öğelerini hedefler ve white-space: nowrap stilini belirtir. Birden çok kelimeden oluşan içerik haritalarının çok satırlı olmasını istemediğimizden, bu işlem çok önemlidir. Bu gönderinin ilerleyen bölümlerinde, bu white-space özelliğinde neden olduğu yatay taşma sorununu ele almak için stiller ekleyeceğiz.

.crumb {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--nav-gap) / 4);

  & > a {
    white-space: nowrap;

    &[aria-current="page"] {
      font-weight: bold;
    }
  }
}

Mevcut sayfa bağlantısının diğerlerinden öne çıkmasını sağlamak için aria-current="page" eklendi. Ekran okuyucu kullanıcıları bağlantının geçerli sayfaya ait olduğuna dair net bir göstergeye sahip olmanın yanı sıra görme engelli kullanıcıların benzer bir kullanıcı deneyimi yaşamalarına yardımcı olmak için öğenin görsel stilini de oluşturduk.

.crumbicon bileşeni, bir SVG simgesini "neredeyse görünmez" <select> öğesiyle yığınlamak için ızgara kullanır.

Izgara Geliştirici Araçları, satır ve sütunun adının yığın olarak adlandırıldığı bir düğmeyle yer paylaşımlı olarak gösterilmektedir.

.crumbicon {
  --crumbicon-size: 3ch;

  display: grid;
  grid: [stack] var(--crumbicon-size) / [stack] var(--crumbicon-size);
  place-items: center;

  & > * {
    grid-area: stack;
  }
}

<select> öğesi, DOM'de son sırada olduğu için yığının üstündedir ve etkileşimlidir. Öğenin hâlâ kullanılabilir olması için bir opacity: .01 stili ekleyin. Böylece, simgenin şekline mükemmel şekilde uyan bir seçim kutusu elde edersiniz. Bu, yerleşik işlevselliği korurken bir <select> öğesinin görünümünü özelleştirmenin güzel bir yoludur.

.disguised-select {
  inline-size: 100%;
  block-size: 100%;
  opacity: .01;
  font-size: min(100%, 16px); /* Defaults to 16px; fixes iOS zoom */
}

Taşma

İçerik haritaları çok uzun bir yolu temsil edebilmelidir. Uygun durumlarda, öğelerin ekrandan yatay olarak çıkarılmasına izin vermenin hayranıyım ve bu içerik haritası bileşeninin iyi değerlendirildiğini düşünüyorum.

.breadcrumbs {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: calc(var(--nav-gap) / 2);

  & > .crumb:last-of-type {
    scroll-snap-align: end;
  }

  @supports (-webkit-hyphens:none) { & {
    scroll-snap-type: none;
  }}
}

Taşma stilleri aşağıdaki kullanıcı deneyimini ayarlamıştır:

  • Fazla kaydırma içeren yatay kaydırma.
  • Yatay kaydırma dolgusu.
  • Son harita üzerinde bir tutturma noktası. Bu, sayfa yüklemesinde, tutturulan ve görüntülenen ilk kırıltma yüklemelerinin olacağı anlamına gelir.
  • Yatay kaydırma ve tutturma efekti kombinasyonlarında sorun yaşayan Safari'deki tutturma noktasını kaldırır.

Medya sorguları

Daha küçük görüntü alanlarına yönelik ince bir düzenleme, "Ana sayfa" etiketini gizlemektir. Yalnızca simgeyi burada bırakırsınız:

@media (width <= 480px) {
  .breadcrumbs .home-label {
    display: none;
  }
}

Karşılaştırma için, içerik haritalarının yanında ana sayfa etiketi olan ve olmayan,

Erişilebilirlik

Hareket

Bu bileşende çok fazla hareket yoktur ancak geçişi bir prefers-reduced-motion işaretiyle sarmalayarak istenmeyen hareketi engelleyebiliriz.

@media (prefers-reduced-motion: no-preference) {
  .crumbicon {
    transition: box-shadow .2s ease;
  }
}

Diğer stillerin hiçbirinin değiştirilmesi gerekmez. Fareyle üzerine gelme ve odaklama efektleri, transition olmadan mükemmel ve anlamlıdır. Ancak, hareket uygunsa etkileşime hafif bir geçiş ekleyeceğiz.

JavaScript

Öncelikle, sitenizde veya uygulamanızda kullandığınız yönlendirici türü ne olursa olsun, bir kullanıcı içerik haritalarını değiştirdiğinde URL'nin güncellenmesi ve kullanıcıya uygun sayfayı göstermesi gerekir. İkinci olarak, kullanıcı deneyimini normalleştirmek için, kullanıcılar yalnızca <select> seçeneklerine göz atarken beklenmedik şekilde gezinmelerin gerçekleşmediğinden emin olun.

JavaScript tarafından işlenecek iki kritik kullanıcı deneyimi önlemi değişti: Seçim değişti ve <select> değişiklik etkinliğinin etkinleşmesini önlemeye hazır.

<select> öğesi kullanıldığı için zorunlu etkinlik önleme özelliği gerekir. Windows Edge'de ve muhtemelen diğer tarayıcılarda, kullanıcı klavyeyi kullanarak seçeneklere göz atarken seçili changed etkinliği tetiklenir. Kullanıcı, fareyle üzerine gelme veya odak gibi seçeneği yalnızca sanal olarak belirlediği ancak henüz enter ya da click ile bu seçimi onaylamadığı için bu seçeneği istekli olarak adlandırdım. Eyeger etkinliği, bu bileşen kategorisi değişikliği özelliğini erişilemez hale getirir. Çünkü seçim kutusunu açıp yalnızca bir öğeye göz atmak, etkinliği tetikler ve kullanıcı daha hazır olmadan sayfayı değiştirir.

Daha iyi bir <select> değiştirilmiş etkinlik

const crumbs = document.querySelectorAll('.breadcrumbs select')
const allowedKeys = new Set(['Tab', 'Enter', ' '])
const preventedKeys = new Set(['ArrowUp', 'ArrowDown'])

// watch crumbs for changes,
// ensures it's a full value change, not a user exploring options via keyboard
crumbs.forEach(nav => {
  let ignoreChange = false

  nav.addEventListener('change', e => {
    if (ignoreChange) return
    // it's actually changed!
  })

  nav.addEventListener('keydown', ({ key }) => {
    if (preventedKeys.has(key))
      ignoreChange = true
    else if (allowedKeys.has(key))
      ignoreChange = false
  })
})

Bunun stratejisi, her <select> öğesindeki klavye aşağısındaki etkinlikleri izlemek ve tuşa basılan tuşun gezinme onayı mı (Tab veya Enter) yoksa üç boyutlu gezinme mi (ArrowUp ya da ArrowDown) olduğunu belirlemektir. Bu tespitle, bileşen <select> öğesine ilişkin etkinlik etkinleştiğinde beklemeye veya gitmeye karar verebilir.

Sonuç

Şimdi bunu nasıl yaptığımı öğrendiğinize göre siz nasıl ‽ 🙂

Gelin, yaklaşımlarımızı çeşitlendirelim ve web'de içerik geliştirmenin tüm yollarını öğrenelim. Demo oluşturup beni tweet'le bağlantıları oluşturduğumda bunu aşağıdaki topluluk remiksleri bölümüne ekleyeceğim.

Topluluk remiksleri