نظرة عامة أساسية حول كيفية إنشاء انزلاق سريع الاستجابة خارج التنقل الجانبي
في هذه المشاركة، أود أن أشارككم كيف صممتُ نموذجًا أوّليًا لمكون Sidenav للويب ذا استجابة سريعة وذا الحالة ويدعم التنقل بلوحة المفاتيح ويعمل مع JavaScript أو بدونه ويعمل عبر المتصفحات. جرِّب العرض التوضيحي.
إليك نسخة من هذه المشاركة على YouTube إذا كنت تفضّل ذلك:
نظرة عامة
من الصعب إنشاء نظام تنقل سريع الاستجابة. سيكون بعض المستخدمين على لوحة مفاتيح، وسيكون لدى بعضهم أجهزة كمبيوتر مكتبية قوية، وسيزور البعض الآخر من جهاز محمول صغير. من المفترض أن يتمكّن جميع الزوّار من فتح القائمة وإغلاقها.
أساليب الويب
في هذا استكشاف المكونات، استمتعتُ بالجمع بين بعض الميزات المهمة لمنصات الويب:
- خدمة مقارنة الأسعار (CSS)
:target
- شبكة CSS
- transforms 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
كي لا يدخل تركيز لوحة المفاتيح إلى العنصر خارج الشاشة.
عندما أبدأ في تنفيذ الرسوم المتحركة للحركة، أريد أن أبدأ بإمكانية الوصول في مقدمة أولوياتي.
حركة يسهل الوصول إليها
لن يرغب الجميع في تجربة حركة التمرير. وفي الحل الذي نقدمه، يتم تطبيق هذا الخيار المفضّل
عن طريق ضبط متغيّر CSS --duration
داخل الاستعلام عن الوسائط. تمثل قيمة الاستعلام عن الوسائط هذه تفضيل
نظام تشغيل المستخدم للحركة (إن كان متاحًا).
#sidenav-open {
--duration: .6s;
}
@media (prefers-reduced-motion: reduce) {
#sidenav-open {
--duration: 1ms;
}
}
الآن عندما يتم تمرير شريط التنقل الجانبي مفتوحًا ومغلقًا، إذا كان المستخدم يفضل الحركة المنخفضة، أحرك العنصر على الفور إلى العرض، مع الحفاظ على الحالة بدون حركة.
التحوّل أو التحويل أو الترجمة
Sidenav out (تلقائي)
لضبط الحالة التلقائية للتنقّل الجانبي على الأجهزة الجوّالة على حالة خارج الشاشة،
أضع العنصر باستخدام 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 في
عندما يتطابق العنصر #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: demo & code
- @a_nurella مع ريمكس لتطبيق Glitch: فيديو توضيحي ورمز
- @EvroMalarkey مع HTML/CSS/JS: الإصدار التجريبي والرمز البرمجي