نظرة عامة أساسية حول كيفية إنشاء شريط تنقّل جانبي منزلق ومتجاوب
في هذه المشاركة، أريد أن أشاركك كيفية إنشاء نموذج أولي لمكوّن Sidenav على الويب متجاوب، وحساس للحالة، ويتوافق مع التنقّل باستخدام لوحة المفاتيح، ويعمل مع JavaScript وبدونها، ويعمل على جميع المتصفّحات. جرِّب العرض التوضيحي.
إذا كنت تفضّل مشاهدة فيديو، إليك نسخة من هذا المنشور على YouTube:
نظرة عامة
من الصعب إنشاء نظام تنقّل سريع الاستجابة. سيتوفّر لدى بعض المستخدمين لوحة مفاتيح، وسيتوفّر لدى البعض الآخر أجهزة كمبيوتر سطح مكتب قوية، وسيزور البعض الموقع الإلكتروني من جهاز جوّال صغير. يجب أن يتمكّن كل زائر من فتح القائمة وإغلاقها.
Web Tactics
في استكشاف المكوّنات هذا، استمتعتُ بدمج بعض الميزات المهمة في منصة الويب:
- CSS
:target
- الشبكة في CSS
- تحويلات CSS
- طلبات بحث الوسائط في CSS لعرض المحتوى والإعدادات المفضّلة للمستخدم
- JavaScript من أجل
focus
تحسينات تجربة المستخدم
يتضمّن الحلّ الذي أقدّمه شريطًا جانبيًا واحدًا ويتم تبديله فقط عند إطار عرض "متوافق مع الأجهزة الجوّالة" بحجم 540px
أو أقل.
سيكون 540px
نقطة توقّف للتبديل بين التنسيق التفاعلي للأجهزة الجوّالة والتنسيق الثابت لأجهزة الكمبيوتر.
الفئة الصورية :target
في CSS
يضبط أحد الروابط <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
في السابق، كنت أستخدم فقط تخطيطات وعناصر الشريط الجانبي الثابتة أو ذات الموضع المطلق. في المقابل، يتيح لنا تنسيق الشبكة، من خلال بناء الجملة 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
لكي لا ينتقل تركيز لوحة المفاتيح إلى العنصر خارج الشاشة
عندما أبدأ في تنفيذ الصور المتحركة، أريد أن أضع سهولة الاستخدام في الاعتبار أولاً.
حركة مناسبة
لن يرغب الجميع في تجربة حركة الانزلاق. في الحلّ الذي نقدّمه، يتم تطبيق هذا الخيار المفضّل من خلال تعديل متغيّر --duration
CSS داخل طلب بحث وسائط. تمثّل قيمة طلب البحث عن الوسائط هذا إعدادات نظام التشغيل المفضّلة لدى المستخدمين بشأن الحركة (إذا كانت متاحة).
#sidenav-open {
--duration: .6s;
}
@media (prefers-reduced-motion: reduce) {
#sidenav-open {
--duration: 1ms;
}
}
الآن، عندما ينزلق الشريط الجانبي للفتح والإغلاق، إذا كان المستخدم يفضّل تقليل الحركة، أنقل العنصر على الفور إلى العرض، مع الحفاظ على الحالة بدون حركة.
الانتقال والتحويل والترجمة
إخفاء الشريط الجانبي (الإعداد التلقائي)
لضبط الحالة التلقائية لشريط التنقّل الجانبي على الأجهزة الجوّالة على حالة خارج الشاشة، أضع العنصر باستخدام 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
مع :target
، اضبط موضع translateX()
على القاعدة الأساسية 0
،
وشاهِد كيف ينقل CSS العنصر من موضعه الخارجي -110vw
إلى موضعه الداخلي 0
خلال var(--duration)
عند تغيير تجزئة عنوان URL.
@media (max-width: 540px) {
#sidenav-open:target {
visibility: visible;
transform: translateX(0);
transition:
transform var(--duration) var(--easeOutExpo);
}
}
مستوى ظهور الانتقال
والهدف الآن هو إخفاء القائمة عن برامج قراءة الشاشة عندما تكون غير ظاهرة،
حتى لا تركّز الأنظمة على قائمة غير ظاهرة على الشاشة. أحقّق ذلك من خلال ضبط انتقال مستوى الظهور عند تغيُّر قيمة :target
.
- عند الانتقال إلى الداخل، لا تغيِّر مستوى العرض، بل اجعل العنصر مرئيًا على الفور حتى أتمكّن من رؤية العنصر وهو ينزلق إلى الداخل وقبول التركيز.
- عند الخروج، يجب إيقاف إمكانية الظهور مؤقتًا، ثم تأخيرها، بحيث يتم التبديل إلى
hidden
في نهاية عملية الإيقاف المؤقت.
تحسينات على تجربة المستخدم في ما يتعلّق بتسهيل الاستخدام
الروابط
يعتمد هذا الحلّ على تغيير عنوان 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));
}
إضافة JavaScript
اضغط على escape
للإغلاق
من المفترض أن يؤدي الضغط على المفتاح Escape
في لوحة المفاتيح إلى إغلاق القائمة، أليس كذلك؟ لنبدأ عملية الربط.
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', event => {
if (event.code === 'Escape') document.location.hash = '';
});
سجلّ المتصفح
لمنع تفاعل الفتح والإغلاق من تكديس إدخالات متعددة في سجلّ المتصفّح، أضِف JavaScript المضمّن التالي إلى زر الإغلاق:
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>
سيؤدي هذا إلى إزالة إدخال سجلّ عنوان URL عند الإغلاق، وكأنّ القائمة لم يتم فتحها أبدًا.
تجربة المستخدم في وضع التركيز
يساعدنا المقتطف التالي في التركيز على زري الفتح والإغلاق بعد فتحهما أو إغلاقهما. أريد أن أسهّل عملية التبديل.
sidenav.addEventListener('transitionend', e => {
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? document.querySelector('#sidenav-close').focus()
: document.querySelector('#sidenav-button').focus();
})
عند فتح الشريط الجانبي، ركِّز على زر الإغلاق. عند إغلاق الشريط الجانبي، يجب نقل التركيز إلى زر الفتح. أفعل ذلك من خلال استدعاء focus()
على العنصر في JavaScript.
الخاتمة
بعد أن عرفت كيف فعلت ذلك، كيف كنت ستتصرف؟ وهذا يؤدي إلى بنية مكونات ممتعة. مَن سيُنشئ الإصدار الأول الذي يتضمّن خانات؟ 🙂
لنستكشف معًا مختلف الطرق التي يمكننا اتّباعها لإنشاء تطبيقات ومواقع إلكترونية على الويب. أنشئ Glitch، وغرِّد لي بنسختك، وسأضيفها إلى قسم ريمكسات من المنتدى أدناه.
ريمكسات من إنشاء المنتدى
- @_developit مع عناصر مخصّصة: عرض توضيحي ورمز
- @mayeedwin1 باستخدام HTML/CSS/JS: عرض توضيحي ورمز
- @a_nurella مع ريمكس Glitch: عرض توضيحي ورمز
- @EvroMalarkey مع HTML/CSS/JS: عرض توضيحي ورمز