Duyarlı bir yan gezinme paneli oluşturmaya dair temel bir genel bakış
Bu gönderide, duyarlı, durum bilgili, klavyeyle gezinmeyi destekleyen, JavaScript ile ve JavaScript olmadan çalışan ve farklı tarayıcılarda çalışan bir web için Sidenav bileşeninin prototipini nasıl oluşturduğumu sizinle paylaşmak istiyorum. Demoyu deneyin.
Video kullanmayı tercih ederseniz bu gönderinin YouTube versiyonunu kullanabilirsiniz:
Genel bakış
Duyarlı bir gezinme sistemi oluşturmak zordur. Bazı kullanıcılar klavye kullanırken, bazıları güçlü masaüstü bilgisayarlara, bazıları ise küçük mobil cihazlardan ziyaret eder. Ziyaret eden herkes menüyü açıp kapatabilmelidir.
Web Taktikleri
Bu bileşen keşfinde birkaç kritik web platformu özelliğini bir araya getirmekten keyif aldım:
- CSS
:target
- CSS ızgarası
- CSS transforms
- Görüntü alanı ve kullanıcı tercihi için CSS Medya Sorguları
focus
kullanıcı deneyimi geliştirmeleri için JS
Çözümümde bir kenar çubuğu var ve geçiş işlemi yalnızca "mobil" görüntü alanında 540px
veya daha az olduğunda geçiş yapıyor.
540px
, mobil etkileşimli düzen ile statik masaüstü düzeni arasında geçiş yapmak için kullandığımız ayrılma noktamız olacak.
CSS :target
sözde sınıfı
<a>
bağlantısı, URL karmasını #sidenav-open
, diğeri de boş (''
) olarak ayarlar.
Son olarak, bir öğede karma ile eşleşecek id
bulunur:
<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. Daha sonra, yapay bir sınıf I ile yan gezinmeyi gösterir ve gizler:
@media (max-width: 540px) {
#sidenav-open {
visibility: hidden;
}
#sidenav-open:target {
visibility: visible;
}
}
CSS Izgarası
Geçmişte, yalnızca mutlak veya sabit konumlu
sidenav düzenleri ve bileşenlerini kullanıyordum. Ancak grid-area
söz dizimi sayesinde ızgara, aynı satıra veya sütuna birden fazla öğe atamamıza olanak tanır.
Gruplar
#sidenav-container
birincil düzen öğesi, her biri stack
olarak adlandırılmış 1 satır ve 2 sütun oluşturan bir ızgaradır. Alan kısıtlı olduğunda CSS, <main>
öğesinin tüm alt öğelerini aynı ızgara adına atar ve tüm öğeler aynı alana yerleştirilerek 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 gezinmeyi içeren animasyon öğesidir. 2 alt öğesi vardır: [nav]
adlı gezinme kapsayıcısı ve menüyü kapatmak için kullanılan [escape]
adlı bir arka plan <a>
.<nav>
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
Menü yer paylaşımı ve negatif alanı kapat düğmesi için istediğiniz oranı bulmak üzere 2fr
ve 1fr
ayarlarını yapın.
CSS 3D dönüştürmeleri ve geçişleri
Düzenimiz artık mobil görüntü alanı boyutunda üst üste dizilmiş. Ben yeni stiller ekleyene kadar varsayılan olarak makalemiz yer paylaşımlı olarak gösterilir. Sonraki bölümde ele aldığım kullanıcı deneyiminden bazıları şunlar:
- Açıp kapatarak animasyon
- Yalnızca kullanıcı buna izin veriyorsa hareketle animasyon kullan
- Klavye odağının ekran dışı öğeye girmemesi için
visibility
animasyonu canlandırılır
Hareket animasyonlarını uygulamaya başladığımda, öncelikle erişilebilirlikle başlamak istiyorum.
Erişilebilir hareket
Herkes kayan hareket deneyimi istemez. Çözümümüzde bu tercih, medya sorgusu içindeki bir --duration
CSS değişkeni ayarlanarak uygulanır. Bu medya sorgusu değeri, kullanıcının işletim sistemi tercihini (varsa) temsil eder.
#sidenav-open {
--duration: .6s;
}
@media (prefers-reduced-motion: reduce) {
#sidenav-open {
--duration: 1ms;
}
}
Yan gezinme panelimiz açılıp kapanıyorken, kullanıcı daha az hareketi tercih ederse öğeyi anında görünüme taşıyarak hareket olmadan durumunu koruyorum.
Geçiş, dönüştürme, çeviri
Yana gezinme (varsayılan)
Mobil cihazda kenar gezinmemizin varsayılan durumunu ekran dışı duruma ayarlamak için öğeyi transform: translateX(-110vw)
ile konumlandırıyorum.
Not: Yan gezinme bölmesinin box-shadow
(gizlendiğinde) ana görüntü alanına göz atmaması için -100vw
adlı tipik ekran dışı koduna 10vw
bir tane daha ekledim.
@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);
}
}
Yandaki bölmede
#sidenav
öğesi :target
olarak eşleştiğinde translateX()
konumunu 0
ana tabanı olarak ayarlayın ve URL karması değiştirildiğinde CSS'nin öğeyi -110vw
konumundan var(--duration)
üzerindeki 0
"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üğü
Buradaki amaç, menü kullanılmadığında menünün ekran okuyuculardan
gizlenmesini sağlamaktır. Böylece sistemler odak dışındaki menüye odaklanmaz. Bunu, :target
değiştiğinde bir
görünürlük geçişi ayarlayarak yapıyorum.
- İçeri girerken görünürlüğü değiştirmeyin; hemen görünür olmalıdır. Böylece öğenin kaydığını ve odağı kabul edebileceğim.
- Dışarı çıkarken görünürlüğü değiştirin ancak geçişi geciktirin. Böylece, geçişin sonunda
hidden
dönüşür hale gelir.
Erişilebilirlikle ilgili kullanıcı deneyimi geliştirmeleri
Bağlantılar
Bu çözüm, durumun yönetilmesi için URL'nin değiştirilmesine dayanır.
Doğal olarak <a>
öğesi burada kullanılmalıdır. Ayrıca bu öğeye ücretsiz olarak bazı güzel erişilebilirlik özellikleri de sahip olur. Etkileşimli öğelerimizi, amacı açıkça ifade eden 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 kullanım amacını net bir şekilde belirtiyor.
:is(:hover, :focus)
Bu kullanışlı CSS işlevsel sözde seçicisi, vurgulu öğeleri paylaşarak bunların üzerine gelme stillerimize hızla dahil edebilmemizi sağlıyor.
.hamburger:is(:hover, :focus) svg > line {
stroke: hsl(var(--brandHSL));
}
JavaScript'e ekleme
Kapatmak için escape
tuşlarına basın
Klavyenizdeki Escape
tuşu menüyü kapatmalı, doğru mu? Bunu kabloyla açalım.
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', event => {
if (event.code === 'Escape') document.location.hash = '';
});
Tarayıcı geçmişi
Açık ve kapalı etkileşiminin birden fazla girişi tarayıcı geçmişine yığmasını önlemek için kapat düğmesine aşağıdaki satır içi JavaScript'i ekleyin:
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>
Bu işlem, kapanışta URL geçmişi girişini kaldırır ve menüyü hiç açılmamış gibi gösterir.
Kullanıcı deneyimine odaklanma
Sonraki snippet, açılıp kapatıldıktan sonra açma ve kapatma düğmelerine odaklanmamıza yardımcı olur. Geçişi 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 paneli açıldığında kapat düğmesine odaklanın. Yan gezinme paneli kapandığında
aç düğmesine odaklanın. Bunu, JavaScript'teki öğede focus()
yöntemini çağırarak yapıyorum.
Sonuç
Şimdi bunu nasıl yaptığımı biliyorsun, şimdi nasıl yaparsın? Bu da eğlenceli bir bileşen mimarisi oluşturur. Slotlarla ilk sürümü kim yapacak? 🙂
Gelin, yaklaşımlarımızı çeşitlendirelim ve web üzerinde geliştirme yapmanın tüm yollarını öğrenelim. Oluşturduğunuz Glitch'i tweet'le paylaşabilirsiniz. Yayınladığınız videoyu aşağıdaki Topluluk remiksleri bölümüne eklerim.
Topluluk remiksleri
- Özel öğeler içeren @_developit: demo ve kod
- HTML/CSS/JS ile @mayeedwin1: demo ve kod
- Glitch Remiks ile @a_nurella: demo ve kod
- HTML/CSS/JS ile @EvroMalarkey: demo ve kod