ساخت یک جزء sidenav

یک مرور کلی از نحوه ساخت یک sidenav کشویی پاسخگو

در این پست می‌خواهم با شما به اشتراک بگذارم که چگونه یک جزء Sidenav را برای وب نمونه‌سازی کردم که واکنش‌گرا، حالت‌پذیر است، از ناوبری صفحه‌کلید پشتیبانی می‌کند، با و بدون جاوا اسکریپت کار می‌کند و در مرورگرها کار می‌کند. نسخه ی نمایشی را امتحان کنید.

اگر ویدیو را ترجیح می دهید، در اینجا یک نسخه YouTube از این پست وجود دارد:

نمای کلی

ساختن یک سیستم ناوبری پاسخگو کار سختی است. برخی از کاربران روی صفحه کلید خواهند بود، برخی دسکتاپ قدرتمند خواهند داشت و برخی از یک دستگاه تلفن همراه کوچک بازدید می کنند. هر کسی که بازدید می کند باید بتواند منو را باز و بسته کند.

نسخه ی نمایشی طرح پاسخگو از دسکتاپ به موبایل
طرح زمینه روشن و تاریک در iOS و Android

تاکتیک های وب

در این کاوش مؤلفه، من از ترکیب چند ویژگی مهم پلت فرم وب لذت بردم:

  1. CSS :target
  2. شبکه CSS
  3. CSS تبدیل می شود
  4. پرس و جوهای رسانه CSS برای دیدگاه و اولویت کاربر
  5. 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>
نسخه ی نمایشی از تعامل صوتی و صفحه کلید UX.

اکنون دکمه های تعامل اولیه ما به وضوح هدف خود را برای ماوس و صفحه کلید بیان می کنند.

: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() روی عنصر در جاوا اسکریپت انجام می دهم.

نتیجه گیری

حالا که می دانی من چگونه این کار را انجام دادم، شما چطور؟! این باعث می شود معماری اجزای سرگرم کننده ای ایجاد شود! چه کسی می خواهد نسخه اول را با اسلات بسازد؟ 🙂

بیایید رویکردهایمان را متنوع کنیم و همه راه‌های ساخت در وب را بیاموزیم. یک اشکال ایجاد کنید، نسخه خود را برای من توییت کنید ، و من آن را به بخش ریمیکس های انجمن در زیر اضافه می کنم.

ریمیکس های انجمن