Ringkasan dasar tentang cara membuat sidenav geser keluar yang responsif
Dalam postingan ini, saya ingin membagikan cara membuat prototipe komponen Sidenav untuk web yang responsif, memiliki status, mendukung navigasi keyboard, berfungsi dengan dan tanpa JavaScript, serta berfungsi di seluruh browser. Coba demo.
Jika Anda lebih suka video, berikut versi YouTube dari postingan ini:
Ringkasan
Membangun sistem navigasi responsif tidaklah mudah. Beberapa pengguna akan menggunakan keyboard, beberapa akan memiliki desktop yang canggih, dan beberapa akan mengunjungi dari perangkat seluler kecil. Semua pengunjung harus dapat membuka dan menutup menu.
Taktik Web
Dalam eksplorasi komponen ini, saya senang dapat menggabungkan beberapa fitur platform web penting:
- CSS
:target
- Petak CSS
- Transformasi CSS
- Kueri Media CSS untuk area pandang dan preferensi pengguna
- JS untuk peningkatan UX
focus
Solusi saya memiliki satu sidebar dan hanya beralih saat berada di area pandang "seluler" sebesar 540px
atau kurang.
540px
akan menjadi titik henti sementara untuk beralih antara tata letak interaktif seluler dan tata letak desktop statis.
Pseudo-class :target
CSS
Satu link <a>
menetapkan hash URL ke #sidenav-open
dan link lainnya ke kosong (''
).
Terakhir, elemen memiliki id
untuk mencocokkan hash:
<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>
Mengklik setiap link ini akan mengubah status hash URL halaman kita, lalu dengan class pseudo, saya menampilkan dan menyembunyikan sidenav:
@media (max-width: 540px) {
#sidenav-open {
visibility: hidden;
}
#sidenav-open:target {
visibility: visible;
}
}
Petak CSS
Sebelumnya, saya hanya menggunakan komponen dan tata letak sidenav posisi absolut atau tetap. Namun, petak, dengan sintaksis grid-area
-nya,
memungkinkan kita menetapkan beberapa elemen ke baris atau kolom yang sama.
Stack
Elemen tata letak utama #sidenav-container
adalah petak yang membuat 1 baris dan 2 kolom,
masing-masing 1 baris dan 1 kolom diberi nama stack
. Jika ruang terbatas, CSS menetapkan semua turunan elemen <main>
ke nama petak yang sama, menempatkan semua elemen ke dalam ruang yang sama, sehingga membuat tumpukan.
#sidenav-container {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
min-height: 100vh;
}
@media (max-width: 540px) {
#sidenav-container > * {
grid-area: stack;
}
}
Latar belakang menu
<aside>
adalah elemen animasi yang berisi navigasi samping. Elemen ini memiliki
2 turunan: penampung navigasi <nav>
bernama [nav]
dan latar belakang <a>
bernama [escape]
, yang digunakan untuk menutup menu.
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
Sesuaikan 2fr
& 1fr
untuk menemukan rasio yang Anda sukai untuk overlay menu dan tombol tutup ruang negatifnya.
Transformasi & transisi 3D CSS
Tata letak kita sekarang ditumpuk pada ukuran area pandang seluler. Hingga saya menambahkan beberapa gaya baru, gaya ini akan menempatkan artikel secara default. Berikut beberapa UX yang saya targetkan di bagian berikutnya:
- Animasi buka dan tutup
- Hanya animasi dengan gerakan jika pengguna mengizinkannya
- Menganimasikan
visibility
agar fokus keyboard tidak memasuki elemen di luar layar
Saat mulai menerapkan animasi gerakan, saya ingin memulai dengan mempertimbangkan aksesibilitas.
Gerakan yang dapat diakses
Tidak semua orang menginginkan pengalaman gerakan geser keluar. Dalam solusi kami, preferensi ini
diterapkan dengan menyesuaikan variabel CSS --duration
di dalam kueri media. Nilai kueri media ini mewakili
preferensi sistem operasi pengguna untuk gerakan (jika tersedia).
#sidenav-open {
--duration: .6s;
}
@media (prefers-reduced-motion: reduce) {
#sidenav-open {
--duration: 1ms;
}
}
Sekarang, saat sidenav kita terbuka dan tertutup, jika pengguna lebih memilih gerakan yang dikurangi, saya langsung memindahkan elemen ke tampilan, mempertahankan status tanpa gerakan.
Transisi, transformasi, terjemahan
Sidenav keluar (default)
Untuk menetapkan status default sidenav di perangkat seluler ke status di luar layar,
saya memosisikan elemen dengan transform: translateX(-110vw)
.
Perhatikan, saya menambahkan 10vw
lain ke kode offscreen -100vw
yang biasa,
untuk memastikan box-shadow
sidenav tidak mengintip ke area pandang utama saat disembunyikan.
@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);
}
}
Sidenav dalam
Jika elemen #sidenav
cocok dengan :target
, tetapkan posisi translateX()
ke homebase 0
,
dan perhatikan saat CSS menggeser elemen dari posisi keluar -110vw
, ke posisi "masuk"
0
di atas var(--duration)
saat hash URL diubah.
@media (max-width: 540px) {
#sidenav-open:target {
visibility: visible;
transform: translateX(0);
transition:
transform var(--duration) var(--easeOutExpo);
}
}
Visibilitas transisi
Tujuannya sekarang adalah menyembunyikan menu dari pembaca layar saat menu ditampilkan,
sehingga sistem tidak memfokuskan menu ke menu di luar layar. Saya melakukannya dengan menetapkan
transisi visibilitas saat :target
berubah.
- Saat masuk, jangan transisikan visibilitas; langsung terlihat sehingga saya dapat melihat elemen bergeser masuk dan menerima fokus.
- Saat keluar, transisi visibilitas, tetapi tunda, sehingga beralih ke
hidden
di akhir transisi keluar.
Peningkatan UX aksesibilitas
Link
Solusi ini mengandalkan perubahan URL agar status dapat dikelola.
Tentu saja, elemen <a>
harus digunakan di sini, dan mendapatkan beberapa fitur aksesibilitas
yang bagus secara gratis. Mari kita hiasi elemen interaktif dengan label yang dengan jelas menyatakan intent.
<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>
Sekarang tombol interaksi utama kita menyatakan niatnya dengan jelas untuk mouse dan keyboard.
:is(:hover, :focus)
Pseudo-pemilih fungsional CSS yang praktis ini memungkinkan kita menjadi inklusif dengan cepat dengan gaya pengarahan kursor dengan membagikannya dengan fokus juga.
.hamburger:is(:hover, :focus) svg > line {
stroke: hsl(var(--brandHSL));
}
Menambahkan JavaScript
Tekan escape
untuk menutup
Tombol Escape
di keyboard Anda akan menutup menu, bukan? Mari kita hubungkan.
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', event => {
if (event.code === 'Escape') document.location.hash = '';
});
Histori browser
Untuk mencegah interaksi buka dan tutup menumpuk beberapa entri ke dalam histori browser, tambahkan JavaScript inline berikut ke tombol tutup:
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>
Tindakan ini akan menghapus entri histori URL saat ditutup, sehingga seolah-olah menu tidak pernah dibuka.
UX Fokus
Cuplikan berikutnya membantu kita memfokuskan tombol buka dan tutup setelah tombol tersebut terbuka atau tertutup. Saya ingin memudahkan pengalihan.
sidenav.addEventListener('transitionend', e => {
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? document.querySelector('#sidenav-close').focus()
: document.querySelector('#sidenav-button').focus();
})
Saat sidenav terbuka, fokuskan tombol tutup. Saat sidenav ditutup, fokuskan tombol buka. Saya melakukannya dengan memanggil focus()
pada elemen di JavaScript.
Kesimpulan
Setelah Anda tahu cara saya melakukannya, bagaimana Anda melakukannya? Hal ini membuat arsitektur komponen yang menyenangkan. Siapa yang akan membuat versi pertama dengan slot? 🙂
Mari kita diversifikasi pendekatan dan pelajari semua cara untuk mem-build di web. Buat Glitch, tweet versi Anda kepada saya, dan saya akan menambahkannya ke bagian Remix komunitas di bawah.
Remix komunitas
- @_developit dengan elemen kustom: demo & kode
- @mayeedwin1 dengan HTML/CSS/JS: demo & kode
- @a_nurella dengan Remix Glitch: demo & kode
- @EvroMalarkey dengan HTML/CSS/JS: demo & kode