ساختن مؤلفه sidenav

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

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

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

نمای کلی

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

نمونه چیدمان واکنش‌گرای رایانه به تلفن همراه
زمینه روشن و تیره در iOS و Android

تاکتیک‌های وب

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

  1. سرویس مقایسه قیمت :target
  2. شبکه CSS
  3. تبدیل‌های CSS
  4. پُرسمان‌های رسانه‌ای CSS برای نمای هدف و اولویت کاربر
  5. JS برای focus بهبودهای تجربه کاربری

راه حل من یک نوار کناری دارد و فقط زمانی تغییر می‌کند که در نمای «تلفن همراه» 540px یا کمتر باشد. 540px نقطه توقف ما برای جابه‌جایی بین چیدمان تعاملی تلفن همراه و چیدمان ایستا رایانه خواهد بود.

شبه‌کلاس CSS :target

یک پیوند <a> درهم‌سازی نشانی وب را روی #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>

کلیک کردن روی هرکدام از این پیوندها، وضعیت درهم‌سازی نشانی وب صفحه ما را تغییر می‌دهد، سپس با کلاس کاذب، sidenav را نشان می‌دهم و پنهان می‌کنم:

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
  }

  #sidenav-open:target {
    visibility: visible;
  }
}

شبکه CSS

در گذشته، فقط از طرح‌بندی‌ها و مؤلفه‌های sidenav با موقعیت مطلق یا ثابت استفاده می‌کردم. اما Grid با نحو grid-area خود به ما امکان می‌دهد چندین عنصر را به یک ردیف یا ستون اختصاص دهیم.

پشته‌ها

عنصر چیدمان اصلی #sidenav-container شبکه‌ای است که ۱ ردیف و ۲ ستون ایجاد می‌کند، که هرکدام 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> عنصر پویانمایی است که حاوی پیمایش کناری است. این عنصر ۲ فرزند دارد: محفظه پیمایش <nav> با نام [nav] و پساویز <a> با نام [escape] که برای بستن منو استفاده می‌شود.

#sidenav-open {
  display: grid;
  grid-template-columns: [nav] 2fr [escape] 1fr;
}

2fr و 1fr را تنظیم کنید تا نسبت موردنظرتان را برای هم‌پوشانی منو و دکمه بستن فضای منفی آن پیدا کنید.

نمونه‌ای از آنچه هنگام تغییر نسبت اتفاق می‌افتد.

انتقال‌ها و تبدیل‌های سه‌بعدی CSS

اکنون چیدمان ما در اندازه ناحیه نمایش تلفن همراه پشته شده است. تا زمانی که سبک‌های جدیدی اضافه کنم، به‌طور پیش‌فرض روی مقاله ما قرار می‌گیرد. در اینجا چند تجربه کاربری را که در بخش بعدی هدف قرار داده‌ام آورده‌ام:

  • پویانمایی باز و بسته شدن
  • فقط درصورتی پویانمایی با حرکت انجام شود که کاربر با آن موافق باشد
  • visibility را پویانمایی کنید تا تمرکز صفحه‌کلید وارد عنصر خارج از صفحه نشود

As I begin to implement motion animations, I want to start with accessibility top of mind.

حرکت دسترس‌پذیر

همه افراد تجربه حرکت بیرون‌لغز را نمی‌خواهند. در راه‌حل ما، این اولویت با تنظیم متغیر --duration CSS در پُرسمان رسانه‌ای اعمال می‌شود. این مقدار پرسمان رسانه نشان‌دهنده اولویت سیستم‌عامل کاربر برای حرکت است (درصورت دردسترس بودن).

#sidenav-open {
  --duration: .6s;
}

@media (prefers-reduced-motion: reduce) {
  #sidenav-open {
    --duration: 1ms;
  }
}
نمونه‌ای از تعامل با و بدون اعمال مدت.

اکنون وقتی پیمایش کناری ما باز و بسته می‌شود، اگر کاربر کاهش حرکت را ترجیح دهد، من فوراً عنصر را به نما منتقل می‌کنم و وضعیت را بدون حرکت حفظ می‌کنم.

انتقال، تبدیل، ترجمه

Sidenav out (default)

برای تنظیم حالت پیش‌فرض پیمایش کناری در تلفن همراه روی حالت خارج از صفحه، عنصر را با transform: translateX(-110vw) جای‌گذاری می‌کنم.

توجه: من 10vw دیگری به کد معمول خارج از صفحه -100vw اضافه کردم، تا مطمئن شوم که box-shadow پیمایش کناری وقتی پنهان است، به نمای اصلی وارد نمی‌شود.

@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 in

When the #sidenav element matches as :target, set the translateX() position to homebase 0, and watch as CSS slides the element from its out position of -110vw, to its "in" position of 0 over var(--duration) when the URL hash is changed.

@media (max-width: 540px) {
  #sidenav-open:target {
    visibility: visible;
    transform: translateX(0);
    transition:
      transform var(--duration) var(--easeOutExpo);
  }
}

رؤیت‌پذیری گذار

اکنون هدف این است که وقتی منو بسته است، آن را از صفحه‌خوان‌ها پنهان کنیم، تا سیستم‌ها روی منوی خارج از صفحه تمرکز نکنند. این کار را با تنظیم انتقال نمایان بودن هنگام تغییر :target انجام می‌دهم.

  • When going in, don't transition visibility; be visible right away so I can see the element slide in and accept focus.
  • هنگام خروج، نمایان بودن را انتقال دهید اما آن را به‌تأخیر بیندازید تا در پایان انتقال خروج به hidden تغییر کند.

بهبودهای تجربه کاربری دسترس‌پذیری

این راه‌حل بر تغییر نشانی وب برای مدیریت وضعیت متکی است. طبیعتاً، عنصر <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>

با این کار، ورودی سابقه نشانی وب هنگام بسته شدن برداشته می‌شود، به‌گونه‌ای که انگار منو هرگز باز نشده است.

تجربه کاربری تمرکز

قطعه کد بعدی به ما کمک می‌کند تا پس‌از باز یا بسته شدن دکمه‌های باز و بسته کردن، تمرکز را روی آن‌ها قرار دهیم. می‌خواهم جابه‌جایی را آسان کنم.

sidenav.addEventListener('transitionend', e => {
  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
      ? document.querySelector('#sidenav-close').focus()
      : document.querySelector('#sidenav-button').focus();
})

وقتی پیمایش کناری باز می‌شود، روی دکمه بستن تمرکز کنید. وقتی پیمایش کناری بسته می‌شود، روی دکمه باز کردن تمرکز کنید. این کار را با فراخوانی focus() در عنصر در جاوا اسکریپت انجام می‌دهم.

نتیجه‌گیری

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

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

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