یک مرور کلی از نحوه ساخت یک sidenav کشویی پاسخگو
در این پست میخواهم با شما به اشتراک بگذارم که چگونه یک جزء Sidenav را برای وب نمونهسازی کردم که واکنشگرا، حالتپذیر است، از ناوبری صفحهکلید پشتیبانی میکند، با و بدون جاوا اسکریپت کار میکند و در مرورگرها کار میکند. نسخه ی نمایشی را امتحان کنید.
اگر ویدیو را ترجیح می دهید، در اینجا یک نسخه YouTube از این پست وجود دارد:
نمای کلی
ساختن یک سیستم ناوبری پاسخگو کار سختی است. برخی از کاربران روی صفحه کلید خواهند بود، برخی دسکتاپ قدرتمند خواهند داشت و برخی از یک دستگاه تلفن همراه کوچک بازدید می کنند. هر کسی که بازدید می کند باید بتواند منو را باز و بسته کند.
تاکتیک های وب
در این کاوش مؤلفه، من از ترکیب چند ویژگی مهم پلت فرم وب لذت بردم:
- CSS
:target
- شبکه CSS
- CSS تبدیل می شود
- پرس و جوهای رسانه CSS برای دیدگاه و اولویت کاربر
- JS برای بهبود
focus
UX
راه حل من دارای یک نوار کناری است و تنها زمانی که در یک نمای "موبایل" 540px
یا کمتر باشد تغییر می کند. 540px
نقطه شکست ما برای جابهجایی بین طرحبندی تعاملی تلفن همراه و طرحبندی استاتیک دسکتاپ خواهد بود.
CSS :target
یکی از پیوندهای <a>
هش url را روی #sidenav-open
و دیگری خالی ( ''
) قرار می دهد. در نهایت، یک عنصر دارای id
مطابقت با هش است:
<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>
با کلیک بر روی هر یک از این پیوندها، وضعیت هش URL صفحه ما تغییر می کند، سپس با یک کلاس شبه، نوار جانبی را نشان داده و پنهان می کنم:
@media (max-width: 540px) {
#sidenav-open {
visibility: hidden;
}
#sidenav-open:target {
visibility: visible;
}
}
شبکه CSS
در گذشته، من فقط از طرحبندیها و مؤلفههای sidenav موقعیت مطلق یا ثابت استفاده میکردم. گرید گرید، با نحو grid-area
، به ما اجازه می دهد چندین عنصر را به یک سطر یا ستون اختصاص دهیم.
پشته ها
عنصر طرحبندی اولیه #sidenav-container
یک شبکه است که 1 سطر و 2 ستون ایجاد میکند که 1 مورد از هر کدام stack
نام دارد. هنگامی که فضا محدود است، CSS همه فرزندان عنصر <main>
را به یک نام شبکه اختصاص می دهد، همه عناصر را در یک فضا قرار می دهد و یک پشته ایجاد می کند.
#sidenav-container {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
min-height: 100vh;
}
@media (max-width: 540px) {
#sidenav-container > * {
grid-area: stack;
}
}
پس زمینه منو
<aside>
عنصر متحرکی است که شامل ناوبری جانبی است. دارای 2 فرزند است: محفظه ناوبری <nav>
به نام [nav]
و پس زمینه <a>
به نام [escape]
که برای بستن منو استفاده می شود.
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
2fr
و 1fr
را تنظیم کنید تا نسبتی را که برای پوشش منو و دکمه بستن فضای منفی آن دوست دارید پیدا کنید.
CSS 3D تبدیل و انتقال
طرحبندی ما اکنون در یک اندازه نمای موبایل انباشته شده است. تا زمانی که چند سبک جدید اضافه کنم، به طور پیشفرض روی مقاله ما همپوشانی دارد. در اینجا برخی از UX وجود دارد که در بخش بعدی برای آنها عکس میگیرم:
- باز و بسته کردن را متحرک کنید
- فقط در صورتی که کاربر با آن موافق باشد، با حرکت متحرک کنید
-
visibility
متحرک کنید تا فوکوس صفحه کلید وارد عنصر خارج از صفحه نشود
همانطور که من شروع به پیاده سازی انیمیشن های حرکتی می کنم، می خواهم با قابلیت دسترسی شروع کنم.
حرکت قابل دسترس
همه نمی خواهند تجربه حرکت اسلاید بیرون را داشته باشند. در راه حل ما این اولویت با تنظیم یک متغیر CSS --duration
در داخل یک درخواست رسانه اعمال می شود. این مقدار درخواست رسانه، ترجیح سیستم عامل کاربر را برای حرکت (در صورت وجود) نشان می دهد.
#sidenav-open {
--duration: .6s;
}
@media (prefers-reduced-motion: reduce) {
#sidenav-open {
--duration: 1ms;
}
}
اکنون وقتی sidenav ما به صورت کشویی باز و بسته می شود، اگر کاربر حرکت کاهش یافته را ترجیح دهد، من فوراً عنصر را به نمای منتقل می کنم و حالت بدون حرکت را حفظ می کنم.
انتقال، تبدیل، ترجمه
Sidenav out (پیشفرض)
برای تنظیم حالت پیشفرض sidenav ما در موبایل به حالت خارج از صفحه، عنصر را با transform: translateX(-110vw)
.
توجه داشته باشید، من 10vw
دیگر را به کد معمولی خارج از صفحه -100vw
اضافه کردم تا اطمینان حاصل کنم که box-shadow
sidenav زمانی که مخفی است به نمای اصلی نگاه نمی کند.
@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 در
هنگامی که عنصر #sidenav
با :target
مطابقت دارد، موقعیت translateX()
را روی homebase 0
قرار دهید، و مشاهده کنید که CSS عنصر را از موقعیت خارج از -110vw
به موقعیت "in" آن 0
در طول var(--duration)
میبرد. هنگامی که هش URL تغییر می کند.
@media (max-width: 540px) {
#sidenav-open:target {
visibility: visible;
transform: translateX(0);
transition:
transform var(--duration) var(--easeOutExpo);
}
}
قابلیت مشاهده انتقال
هدف اکنون مخفی کردن منو از صفحهخوانها در زمانی است که منتشر میشود، بنابراین سیستمها تمرکز خود را در منوی خارج از صفحه قرار نمیدهند. من این کار را با تنظیم یک انتقال دید زمانی که :target
تغییر می کند انجام می دهم.
- هنگام ورود به داخل، دید را تغییر ندهید. فورا قابل مشاهده باشد تا بتوانم المان را ببینم که به داخل اسلاید می شود و فوکوس را می پذیرم.
- هنگام بیرون رفتن، دید انتقال را تغییر دهید اما آن را به تأخیر بیندازید، بنابراین در انتهای انتقال به بیرون به
hidden
تبدیل می شود.
پیشرفت های UX دسترسی
پیوندها
این راه حل متکی بر تغییر URL به منظور مدیریت وضعیت است. به طور طبیعی، عنصر <a>
باید در اینجا استفاده شود و برخی از ویژگی های دسترسی خوب را به صورت رایگان دریافت می کند. بیایید عناصر تعاملی خود را با برچسب هایی تزئین کنیم که به وضوح قصد را بیان می کنند.
<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>
اکنون دکمه های تعامل اولیه ما به وضوح هدف خود را برای ماوس و صفحه کلید بیان می کنند.
:is(:hover, :focus)
این شبه انتخابگر کاربردی CSS به ما این امکان را میدهد تا با به اشتراکگذاری سبکهای شناور خود با فوکوس نیز سریعاً آنها را فراگیر کنیم.
.hamburger:is(:hover, :focus) svg > line {
stroke: hsl(var(--brandHSL));
}
روی جاوا اسکریپت بپاشید
escape
را برای بسته شدن فشار دهید
کلید Escape
روی صفحه کلید شما باید منو را ببندد درست است؟ بیایید آن را سیم کشی کنیم.
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', event => {
if (event.code === 'Escape') document.location.hash = '';
});
تاریخچه مرورگر
به منظور جلوگیری از انباشتن چندین ورودی در تاریخچه مرورگر توسط تعامل باز و بسته، جاوا اسکریپت زیر را به صورت درون خطی به دکمه بستن اضافه کنید:
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>
با این کار ورودی تاریخچه URL در بسته شدن حذف میشود و آن را طوری میسازد که انگار منو هرگز باز نشده است.
تمرکز UX
قطعه بعدی به ما کمک می کند تا بعد از باز یا بسته شدن دکمه های باز و بسته، روی آنها تمرکز کنیم. من می خواهم جابجایی را آسان کنم.
sidenav.addEventListener('transitionend', e => {
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? document.querySelector('#sidenav-close').focus()
: document.querySelector('#sidenav-button').focus();
})
وقتی نوار کناری باز شد، روی دکمه بستن تمرکز کنید. وقتی نوار کناری بسته شد، روی دکمه باز کردن تمرکز کنید. من این کار را با فراخوانی focus()
روی عنصر در جاوا اسکریپت انجام می دهم.
نتیجه گیری
حالا که می دانی من چگونه این کار را انجام دادم، شما چطور؟! این باعث می شود معماری اجزای سرگرم کننده ای ایجاد شود! چه کسی می خواهد نسخه اول را با اسلات بسازد؟ 🙂
بیایید رویکردهایمان را متنوع کنیم و همه راههای ساخت در وب را بیاموزیم. یک اشکال ایجاد کنید، نسخه خود را برای من توییت کنید ، و من آن را به بخش ریمیکس های انجمن در زیر اضافه می کنم.
ریمیکس های انجمن
- @_developit با عناصر سفارشی: نسخه ی نمایشی و کد
- @mayeedwin1 با HTML/CSS/JS: نسخه ی نمایشی و کد
- @a_nurella با ریمیکس Glitch: نسخه ی نمایشی و کد
- @EvroMalarkey با HTML/CSS/JS: نسخه ی نمایشی و کد