Duyarlı bir yan gezinme paneli oluşturmaya dair temel bir genel bakış
Bu gönderide, web için duyarlı, durum bilgisine sahip, klavye gezinmesini destekleyen, JavaScript ile ve JavaScript olmadan çalışan ve tarayıcılarda çalışan bir Sidenav bileşeninin prototipini nasıl oluşturduğumu paylaşmak istiyorum. Demoyu deneyin.
Videoyu tercih ediyorsanız bu yayının YouTube sürümünü burada bulabilirsiniz:
Genel Bakış
Duyarlı bir gezinme sistemi oluşturmak zordur. Bazı kullanıcılar klavye kullanırken bazıları güçlü masaüstü bilgisayarlara sahip olur, bazıları ise küçük bir mobil cihazdan 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 dönüşümleri
- 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 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ş için ara noktamız olacak.
CSS :target
sözde sınıfı
Bir <a>
bağlantısı, URL karmasını #sidenav-open
olarak, diğeri ise boş (''
) olarak ayarlar.
Son olarak, bir öğede karmayı eşleştirecek 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ıkladığınızda sayfa URL'mizin karma durumu değişir. Ardından, bir sözde sınıfla yan menüyü gösterir ve 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 kenar çubuğu düzenleri ve bileşenleri kullanıyordum. Ancak grid-area
söz dizimi sayesinde grid, 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. Bu ızgaradaki her sütunun adı stack
olarak belirlenir. Alan kısıtlı olduğunda CSS, <main>
öğesinin tüm alt öğelerini aynı ızgara adına atar, tüm öğeleri aynı alana yerleştirir ve 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. 2 alt öğesi vardır: [nav]
adlı gezinme kapsayıcısı <nav>
ve menüyü kapatmak için kullanılan [escape]
adlı bir arka plan <a>
.
#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ürme işlemleri ve geçişler
Düzenimiz artık mobil görüntü alanı boyutunda yığılmış durumda. Yeni stiller ekleyene kadar varsayılan olarak makalemizin üzerine biniyor. Bu sonraki bölümde hedeflediğim kullanıcı deneyimi özelliklerini aşağıda bulabilirsiniz:
- Açma ve kapama animasyonları
- Yalnızca kullanıcının kabul etmesi durumunda hareketle animasyon oluşturma
- Klavye odağının ekran dışı öğeye girmemesi için
visibility
öğesini hareketlendirin
Hareket animasyonları uygulamaya başladığımda erişilebilirliği göz önünde bulundurarak başlamak istiyorum.
Erişilebilir hareket
Herkes kaydırarak açma hareketi deneyimini istemez. Çö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 sistemi tercihini (varsa) temsil eder.
#sidenav-open {
--duration: .6s;
}
@media (prefers-reduced-motion: reduce) {
#sidenav-open {
--duration: 1ms;
}
}
Artık kullanıcı, yan gezinme menüsünün açılmasını ve kapanmasını tercih ettiğinde, hareketi azaltmayı seçerse öğeyi hareketsiz durumdayken anında görüntüye getiririm.
Geçiş, dönüştürme, çeviri
Yan gezinme menüsü kapalı (varsayılan)
Mobil cihazlarda kenar çubuğumuzun varsayılan durumunu ekran dışında olacak şekilde ayarlamak için öğeyi transform: translateX(-110vw)
ile konumlandırıyorum.
Yan gezinme menüsünün box-shadow
öğesinin gizliyken ana görüntü alanını gözetlemesini önlemek için -100vw
öğesinin tipik ekran dışı 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 menüsü
#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
"yer" 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 görünürlük geçişi ayarlayarak yapıyorum.
- İçeri girerken görünürlüğü geçişli olarak göstermeyin. Öğenin içeri kaydığını ve odağı kabul ettiğini görebilmem için hemen görünür olmalıdır.
- Görünürlük geçişini yapın ancak geçişin sonunda
hidden
olarak görünmesi için geçişi geciktirin.
Erişilebilirlik kullanıcı deneyimi iyileştirmeleri
Bağlantılar
Bu çözüm, durumun yönetilebilmesi için URL'nin değiştirilmesini gerektirir.
Burada doğal olarak <a>
öğesi kullanılmalıdır. Bu öğe, ücretsiz olarak bazı güzel erişilebilirlik özelliklerine sahiptir. 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 amaçları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 ekleme
Kapatmak için escape
tuşuna basın
Klavyenizdeki Escape
tuşu menüyü kapatıyor, değil mi? Kabloları 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çılış ve kapanış etkileşiminin tarayıcı geçmişine birden fazla giriş eklemesini önlemek için kapat düğmesine aşağıdaki JavaScript'i satır içi olarak 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ırır ve menünün hiç açılmamış gibi görünmesini sağlar.
Focus UX
Sonraki snippet, açılıp kapatıldıktan sonra açma ve kapatma düğmelerine odaklanmamıza yardımcı olur. Geçiş yapmayı 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 menüsü açıldığında kapat düğmesine odaklanın. Yan gezinme menüsü kapandığında açık düğmesine odaklanın. Bunu, JavaScript'te öğede focus()
'yi çağırarak yapıyorum.
Sonuç
Bunu nasıl yaptığımı öğrendiğinize göre, siz ne yapardınız? Bu da eğlenceli bir bileşen mimarisi oluşturur. 1. sürümü yuvalarla kim yapacak? 🙂
Yaklaşımlarımızı çeşitlendirelim ve web'de uygulama geliştirmenin tüm yollarını öğrenelim. Bir Glitch oluşturun ve benimle tweet'de paylaşın. Topluluk remiksleri bölümüne ekleyeceğim.
Topluluk remiksleri
- Özel öğelerle @_developit: demo ve kod
- HTML/CSS/JS ile @mayeedwin1: demo ve kod
- @a_nurella'nın Glitch remiksiyle: demo ve kod
- HTML/CSS/JS ile @EvroMalarkey: demo ve kod