Duyarlı bir kayan yan gezinme çubuğu oluşturmaya dair temel bir genel bakış
Bu yayında, web için duyarlı, durum bilgisine sahip, klavyeyle gezinmeyi destekleyen, JavaScript ile ve JavaScript olmadan çalışan ve tarayıcılar arasında çalışan bir Sidenav bileşeninin prototipini nasıl oluşturduğumu paylaşmak istiyorum. Demoyu deneyin.
Video izlemeyi tercih ediyorsanız bu yayının YouTube versiyonunu izleyebilirsiniz:
Genel Bakış
Duyarlı bir gezinme sistemi oluşturmak zordur. Bazı kullanıcılar klavye kullanacak, bazıları güçlü masaüstü bilgisayarlara sahip olacak ve bazıları küçük bir mobil cihazdan ziyaret edecek. Ziyaret eden herkes menüyü açıp kapatabilmelidir.
Web taktikleri
Bu bileşen keşfinde, birkaç önemli web platformu özelliğini birleştirme fırsatı buldum:
- CSS
:target - CSS grid
- CSS dönüşümleri
- Görüntü alanı ve kullanıcı tercihi için CSS medya sorguları
focusKullanıcı deneyimi iyileştirmeleri için JS
Çözümümde bir kenar çubuğu var ve yalnızca 540px veya daha küçük bir "mobil" görüntü alanındayken açılıp kapanıyor.
540px, mobil etkileşimli düzen ile statik masaüstü düzeni arasında geçiş yapmak için kesme noktamız olacak.
CSS :target sözde sınıfı
<a> bağlantılarından biri URL karma değerini #sidenav-open, diğeri ise boş ('') olarak ayarlar.
Son olarak, bir öğe karma değerle eşleşen id değerine sahiptir:
<a href="#sidenav-open" id="sidenav-button" title="Open Menu" aria-label="Open Menu">
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
<aside id="sidenav-open">
…
</aside>
Bu bağlantıların her birini tıklamak, sayfa URL'mizin karma durumunu değiştirir. Ardından, bir sözde sınıf ile yan gezinme panelini gösterip gizlerim:
@media (max-width: 540px) {
#sidenav-open {
visibility: hidden;
}
#sidenav-open:target {
visibility: visible;
}
}
CSS Grid
Geçmişte yalnızca mutlak veya sabit konumlu yan gezinme düzenleri ve bileşenleri kullanıyordum. Ancak ızgara, grid-area söz dizimiyle aynı satıra veya sütuna birden fazla öğe atamamıza olanak tanır.
Gruplar
Birincil düzen öğesi #sidenav-container, 1 satır ve 2 sütun oluşturan bir ızgaradır. Her birinin adı stack şeklindedir. Alan kısıtlı olduğunda CSS, <main> öğesinin tüm alt öğelerini aynı ızgara adına atar ve tüm öğeleri aynı alana yerleştirerek bir yığın oluşturur.
#sidenav-container {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
min-height: 100vh;
}
@media (max-width: 540px) {
#sidenav-container > * {
grid-area: stack;
}
}
Menü arka planı
<aside>, yan gezinme menüsünü içeren animasyonlu öğedir. İki alt öğesi vardır: [nav] adlı gezinme kapsayıcısı <nav> ve menüyü kapatmak için kullanılan [escape] adlı arka plan <a>.
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
Menü yer paylaşımı ve öğeler arasındaki boşluk kapatma düğmesi için istediğiniz oranı bulmak üzere 2fr ve 1fr değerlerini ayarlayın.
CSS 3D dönüştürme işlemleri ve geçişleri
Düzenimiz artık mobil görüntü alanı boyutunda yığılı olarak gösteriliyor. Yeni stiller ekleyene kadar varsayılan olarak makalemizin üzerine yerleştirilir. Bir sonraki bölümde hedeflediğim kullanıcı deneyimi şu şekilde:
- Açma ve kapatma animasyonu
- Yalnızca kullanıcı kabul ederse hareketli animasyon kullanın
- Klavye odağının ekran dışı öğeye girmemesi için
visibilityöğesine animasyon ekleyin
Hareket animasyonlarını uygulamaya başlarken erişilebilirliği ön planda tutmak istiyorum.
Erişilebilir hareket
Herkes kaydırarak açılan hareket deneyimini tercih etmeyebilir. Çözümümüzde bu tercih, bir medya sorgusundaki --duration CSS değişkeni ayarlanarak uygulanır. Bu medya sorgusu değeri, kullanıcının işletim sistemindeki hareket tercihini (varsa) temsil eder.
#sidenav-open {
--duration: .6s;
}
@media (prefers-reduced-motion: reduce) {
#sidenav-open {
--duration: 1ms;
}
}
Artık yan gezinme çubuğumuz kayarak açılıp kapanırken kullanıcı daha az hareket tercih ediyorsa öğeyi anında görünüme taşıyarak durumu hareket olmadan koruyorum.
Geçiş, dönüşüm, çeviri
Yan gezinme çubuğu dışarıda (varsayılan)
Mobil cihazlarda yan gezinme çubuğumuzun varsayılan durumunu ekran dışı olarak ayarlamak için
öğeyi transform: translateX(-110vw) ile konumlandırıyorum.
Yan gezinme çubuğunun box-shadow değerinin, gizlendiğinde ana görüntü alanına girmemesi için tipik ekran dışı -100vw koduna başka bir 10vw eklediğimi unutmayın.
@media (max-width: 540px) {
#sidenav-open {
visibility: hidden;
transform: translateX(-110vw);
will-change: transform;
transition:
transform var(--duration) var(--easeOutExpo),
visibility 0s linear var(--duration);
}
}
Yan gezinme çubuğu
#sidenav öğesi :target ile eşleştiğinde translateX() konumunu ana sayfa 0 olarak ayarlayın ve URL karma değeri değiştirildiğinde CSS'nin öğeyi -110vw olan "dışarıda" konumundan var(--duration) üzerinden 0 olan "içeride" konumuna kaydırmasını izleyin.
@media (max-width: 540px) {
#sidenav-open:target {
visibility: visible;
transform: translateX(0);
transition:
transform var(--duration) var(--easeOutExpo);
}
}
Geçiş görünürlüğü
Şimdi amaç, menü kapalıyken ekran okuyuculardan gizlemek.
Böylece sistemler, ekran dışındaki bir menüye odaklanmaz. Bunu, :target değiştiğinde görünürlük geçişi ayarlayarak yapıyorum.
- Giriş yaparken görünürlük geçişi yapmayın; öğenin kayarak girdiğini ve odağı kabul ettiğini görebilmem için hemen görünür olun.
- Çıkış yaparken görünürlüğü değiştirin ancak geciktirin. Böylece çıkış geçişinin sonunda
hiddendeğerine döner.
Erişilebilirlik kullanıcı deneyimi geliştirmeleri
Bağlantılar
Bu çözüm, durumun yönetilmesi için URL'nin değiştirilmesini gerektirir.
Doğal olarak burada <a> öğesi kullanılmalıdır. Bu öğe, bazı erişilebilirlik özelliklerini ücretsiz olarak sunar. Etkileşimli öğelerimizi, amacını açıkça belirten etiketlerle süsleyelim.
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
<svg>...</svg>
</a>
Artık birincil etkileşim düğmelerimiz, hem fare hem de klavye için amaçlarını net bir şekilde belirtiyor.
:is(:hover, :focus)
Bu kullanışlı CSS işlevsel sözde seçici, fareyle üzerine gelme stillerimizi odakla da paylaşarak hızlı bir şekilde kapsayıcı olmamızı sağlar.
.hamburger:is(:hover, :focus) svg > line {
stroke: hsl(var(--brandHSL));
}
JavaScript ekleme
Kapatmak için escape tuşuna basın
Klavyenizdeki Escape tuşu menüyü kapatır, değil mi? Şimdi bunu bağlayalım.
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', event => {
if (event.code === 'Escape') document.location.hash = '';
});
Tarayıcı geçmişi
Açma ve kapatma etkileşiminin tarayıcı geçmişine birden fazla giriş eklemesini önlemek için kapatma düğmesine aşağıdaki JavaScript satır içi kodunu ekleyin:
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>
Bu işlem, kapatıldığında URL geçmişi girişini kaldırarak menünün hiç açılmamış gibi görünmesini sağlar.
Odaklanma kullanıcı deneyimi
Sonraki snippet, açma ve kapatma düğmelerine odaklanmamıza yardımcı olur. Açma/kapatma işlemini kolaylaştırmak istiyorum.
sidenav.addEventListener('transitionend', e => {
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? document.querySelector('#sidenav-close').focus()
: document.querySelector('#sidenav-button').focus();
})
Yan gezinme çubuğu açıldığında kapat düğmesine odaklanın. Yan gezinme çubuğu kapandığında
açma düğmesine odaklanın. Bunu, JavaScript'te öğe üzerinde focus() yöntemini çağırarak yapıyorum.
Sonuç
Benim nasıl yaptığımı öğrendiniz. Peki siz nasıl yapardınız? Bu sayede eğlenceli bir bileşen mimarisi elde edersiniz. Yuvalı ilk 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 versiyonunuzu bana tweetleyin, ben de aşağıdaki Topluluk remiksleri bölümüne ekleyeyim.
Topluluk remiksleri
- Özel öğelerle @_developit: demo ve kod
- HTML/CSS/JS ile @mayeedwin1: demo ve kod
- Glitch Remix ile @a_nurella: demo ve kod
- HTML/CSS/JS ile @EvroMalarkey: demo ve kod