نظرة عامة أساسية حول كيفية إنشاء انزلاق سريع الاستجابة خارج التنقل الجانبي
في هذه المشاركة، أود أن أشارككم كيف صممتُ نموذجًا أوليًا لمكون Sidenav للويب ذا استجابة سريعة وذا الحالة ويدعم التنقل بلوحة المفاتيح ويعمل مع JavaScript أو بدونه ويعمل عبر المتصفحات. جرِّب الإصدار التجريبي.
إذا كنت تفضّل الفيديو، يمكنك الاطّلاع على نسخة من هذه المشاركة على YouTube:
نظرة عامة
من الصعب إنشاء نظام تنقل سريع الاستجابة. سيستخدم بعض المستخدمين لوحة مفاتيح، وسيكون لدى البعض أجهزة كمبيوتر مكتبية قوية، وسيستخدم البعض الآخر جهازًا جوّالاً صغيرًا. من المفترض أن يتمكّن جميع من يزور القائمة من فتح القائمة وإغلاقها.
Web Tactics
في استكشاف المكوّنات هذا، كان من دواعي سروري الجمع بين بعض الميزات المهمة لمنصّة الويب:
- خدمة مقارنة الأسعار (CSS)
:target
- شبكة CSS
- عمليات التحويل في CSS
- طلبات CSS Media Queries لإطار العرض والإعدادات المفضّلة للمستخدم
- 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.
الخاتمة
الآن بعد أن عرفت كيف فعلت ذلك، كيف ستفعل ذلك؟ ويؤدي ذلك إلى إنشاء بنية مكونات ممتعة. مَن سينشئ النسخة الأولى التي تتضمّن خانات؟ 🙂
يمكننا تنويع أساليبنا ونتعلم جميع طرق إنشاء المحتوى على الويب. إنشاء خطأ وإرسال تغريدة تتضمن نسختك، وسأضيفها إلى قسم الريمكسات في المنتدى أدناه.
الريمكسات التي أنشأها المستخدمون
- @_developit باستخدام عناصر مخصّصة: الإصدار التجريبي والرمز
- @mayeedwin1 باستخدام HTML/CSS/JS: العرض الترويجي والرمز البرمجي
- @a_nurella أنشأت ريمكس Glitch: العرض الترويجي والرمز
- @EvroMalarkey باستخدام HTML/CSS/JS: العرض الترويجي والرمز البرمجي