يُعلّمك هذا الدرس التطبيقي حول الترميز كيفية إنشاء عنصر تنسيق تنقّل جانبي قابل للانزلاق وسريع الاستجابة على الويب. سننشئ المكوّن أثناء التقدّم، بدءًا من HTML ثم CSS، ثم JavaScript.
يمكنك الاطّلاع على مشاركة مدونتي إنشاء مكوّن Sidenav للتعرّف على ميزات منصة الويب CSS التي تم اختيارها لإنشاء هذا المكوّن.
ضبط إعدادات الجهاز
- انقر على Remix to Edit (إنشاء ريمكس لتعديل المحتوى) ليصبح المشروع قابلاً للتعديل.
- فتح "
app/index.html
"
HTML
أولاً، عليك الحصول على أساسيات إعداد HTML حتى يتوفّر محتوى وبعض المربّعات للعمل معها.
اسقط رمز HTML التالي في علامة <body>
.
<aside></aside>
<main></main>
يحتوي <aside>
على قائمة التنقّل كعنصر مكمّل لعنصر <main>
الذي يحتوي بدوره على محتوى الصفحة الأساسي.
بعد ذلك، سنملأ هذه العناصر الدلالية بباقي محتوى الصفحة.
أضِف عنصر تنقّل وبعض روابط التنقّل ورابط إغلاق داخل العنصر <aside>
.
<aside>
<nav>
<h4>My</h4>
<a href="#">Dashboard</a>
<a href="#">Profile</a>
<a href="#">Preferences</a>
<a href="#">Archive</a>
<h4>Settings</h4>
<a href="#">Accessibility</a>
<a href="#">Theme</a>
<a href="#">Admin</a>
</nav>
<a href="#"></a>
</aside>
تبدو الروابط رائعة داخل عناصر <nav>
، وتبدو عناصر <nav>
رائعة في الأشرطة الجانبية <aside>
.
لا يزال هناك المزيد من الإجراءات التي يمكننا اتّخاذها لتحسين الأداء.
في عنصر المحتوى الرئيسي، أضِف عنوانًا ومقالة لعرض محتوى التنسيق بشكلٍ دلالي.
<main>
<header>
<a href="#sidenav-open" class="hamburger">
<svg viewBox="0 0 50 40">
<line x1="0" x2="100%" y1="10%" y2="10%" />
<line x1="0" x2="100%" y1="50%" y2="50%" />
<line x1="0" x2="100%" y1="90%" y2="90%" />
</svg>
</a>
<h1>Site Title</h1>
</header>
<article>
{put some placeholder content here}
</article>
</main>
يتضمّن العنوان رابطًا لفتح القائمة. يتضمّن الشريط الجانبي زر الإغلاق. سنعرض العناصر ونخفيها قريبًا استنادًا إلى حجم مساحة العرض.
في عنصر <article>
، لصقنا عبارة نائبة. استبدِل " ``" بمحتوى خاص بك، أو الصِق نص Lorem ipsum المتوفّر أدناه:
<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
وهذا المحتوى وطوله هما ما سيؤديان إلى إمكانية تمرير الصفحة عندما تتجاوز ارتفاع إطار العرض.
لقد أضفت إلى الآن عنصرًا على الجانب يتضمّن شريط تنقّل وروابط وطريقة لإغلاق شريط التنقّل الجانبي. أضفت أيضًا عنوانًا وطريقة لفتح شريط التنقّل الجانبي ومقالة إلى العنصر الرئيسي. هذه العبارة واضحة ودلالية ومناسبة لجميع الأوقات، ولكن يمكننا تحسينها وجعلها أكثر وضوحًا للجميع. يمكن وضع علامة على الرابط المفتوح في شريط التنقّل الجانبي بوضوح أكبر.
أضِف السمتَين title
وaria-label
إلى عنصر الرابط المفتوح في العنوان:
<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">
يمكن أيضًا وضع علامة على رمز SVG المفتوح بشكل أكثر وضوحًا. أضِف السمات التالية إلى ملف SVG داخل عنصر الرابط المفتوح:
<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">
يمكن وضع علامة على رابط الإغلاق في شريط التنقّل الجانبي بشكل أكثر وضوحًا.
أضِف السمتَين title
وaria-label
إلى عنصر رابط إغلاق شريط التنقّل الجانبي:
<a href="#"></a>
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
CSS
حان وقت ترتيب العناصر. إنّ المحتوى الرئيسي
وشريط التنقّل الجانبي هما عنصران ثانويان مباشران للعلامة <body>
، لذا يُعدّ هذان العنصران نقطة بداية جيدة.
أضِف ملف CSS التالي إلى css/sidenav.css
لكي يعرض عنصر <body>
العناصر الفرعية.
body {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
@media (max-width: 540px) {
& > :matches(aside, main) {
grid-area: stack;
}
}
}
يعني هذا التنسيق بشكل أساسي: أنشئ صفًا يحمل الاسم stack
يحتوي على كل البيانات،
وعمودَين في هذا الصف، العمود الثاني يحمل الاسم stack
أيضًا. يجب تحديد حجم العمود الأول
حسب الحد الأدنى لاحتياجات المحتوى، ويمكن أن يشغل العمود الثاني المساحة المتبقية.
بعد ذلك، إذا كانت مساحة العرض محدودة بـ 540px
أو أقل، ضَع شريط التنقّل الجانبي وعناصر المحتوى الرئيسي
في الصف والعمود نفسهما، ما يؤدي إلى وضعهما فوق بعضهما في شبكة 1×1.
باستخدام وظيفة التجميع السريع الاستجابة هذه كأساس، يمكننا الآن الاستفادة من حالة شريط عناوين URL لتبديل مستوى ظهور شريط التنقّل الجانبي ونمط انتقاله.
عدِّل عنصر <aside>
مرة أخرى في app/index.html
:
<aside>
<aside id="sidenav-open">
يتيح ذلك لخدمة CSS مطابقة عنصر مع تجزئة عنوان URL معًا. هذا مهم لاستخدام :target
.
يمكن الآن أن يتطابق رقم تعريف العنصر مع تجزئة عنوان URL التي سنضبطها باستخدام علامات <a>
.
بالإضافة إلى ذلك، لتسهيل استهداف JavaScript، أضِف أرقام تعريف للعناصر الرئيسية التي تتحكّم في شريط التنقّل الجانبي. أولاً، أضِف معرّفًا إلى رابط فتح شريط التنقّل الجانبي:
<a href="#sidenav-open" class="hamburger" title="Open Menu" aria-label="Open Menu">
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
بعد ذلك، أضِف معرّفًا إلى رابط إغلاق شريط التنقّل الجانبي:
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
يُختتم هذا القسم بعرض تخطيط التجميع السريع الاستجابة للوحدة الماكرو <body>
، بالإضافة إلى ربطنا بشريط عناوين URL.
لنواصل العمل.
يتميز <aside>
أيضًا بتنسيق أنيق. يحتوي على عنصرَين فرعيَّين، وهما <nav>
الذي يمثّل العنصر الذي يشبه الورق وينزلق للخارج، وعنصر رابط <a>
الإغلاق الذي يضبط عنوان URL على #
.
الرابط غير مرئي على يسار شريط التنقّل المنبثق، وذلك ليتمكّن المستخدمون من "النقر على" العنصر المرئي
لإغلاقه.
أضِف مقتطف CSS التالي إلى css/sidenav.css
:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
أعتقد أنّ النسبة والأسماء كانت لمسة رائعة حقًا، حيث يمكن أن تبرز الشبكة وتمنح المصمّم الكثير من التحكّم.
بعد ذلك، أحتاج إلى تراكب المحتوى الرئيسي بشكل مشروط والاحتفاظ بموقعي
أثناء الانتقال إلى أي جزء من المستند. هذه وظيفة رائعة لـ position: sticky
و
بعض overscroll-behavior
.
أضِف الأنماط التالية إلى شريط التنقّل الجانبي:
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
@media (max-width: 540px) {
position: sticky;
top: 0;
max-height: 100vh;
overflow: hidden auto;
overscroll-behavior: contain;
visibility: hidden; /* not keyboard accessible when closed */
}
}
تضمن هذه الأنماط أن يكون ارتفاع شريط التنقّل الجانبي هو ارتفاع إطار العرض، وأن يتم التمرير عموديًا
ويحتوي على شريط التمرير. من المهم جدًا إخفاء العنصر. بشكلٍ تلقائي،
يتم إخفاء شريط التنقّل الجانبي هذا عندما يكون إطار العرض 540px
أو أصغر. ما لم يكن
أضِف أداة اختيار وهمية :target
إلى العنصر #sidenav-open
:
#sidenav-open {
@media (max-width: 540px) {
&:target {
visibility: visible;
}
}
}
عندما يكون رقم تعريف هذا العنصر وشريط عناوين URL متطابقَين،
اضبط visibility
على visible
. يُرجى فتح القائمة الجانبية بعد الانتقال إلى أسفل الصفحة،
أو محاولة الانتقال إلى أسفل الصفحة عندما تكون القائمة الجانبية مفتوحة. ما رأيك؟
أضِف ملف CSS التالي إلى أسفل app/sidenav.css
:
#sidenav-button,
#sidenav-close {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
user-select: none;
touch-action: manipulation;
@media (min-width: 540px) {
display: none;
}
}
تستهدف هذه الأنماط أزرار الفتح والإغلاق، وتحدّد أنماط النقر واللمس الخاصة بها،
وتخفيها أيضًا عندما تكون مساحات العرض 540px
أو أكبر.
لإضافة لمسة جمالية، لنضيف عمليات تحويل CSS مع تسهيل الاستخدام بشكل ملائم.
أضِف مقتطف CSS التالي إلى css/sidenav.css
:
#sidenav-open {
--easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
--duration: .6s;
...
@media (max-width: 540px) {
...
transform: translateX(-110vw);
will-change: transform;
transition:
transform var(--duration) var(--easeOutExpo),
visibility 0s linear var(--duration);
&:target {
visibility: visible;
transform: translateX(0);
transition: transform var(--duration) var(--easeOutExpo);
}
}
@media (prefers-reduced-motion: reduce) {
--duration: 1ms;
}
}
إضافة بعض JavaScript
من المفترض أن يؤدي الضغط على مفتاح Escape
إلى إغلاق القائمة. أضِف مقتطف JavaScript هذا إلى js/index.js
:
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', e => {
if (e.code === 'Escape') {
document.location.hash = '';
}
});
وهذا الإجراء يستمع إلى حدث رئيسي في عنصر شريط التنقّل الجانبي.
إذا كان Escape
، يتم ضبط تجزئة عنوان URL على فارغة، ما يؤدي إلى إيقاف الانتقال إلى شريط التنقّل الجانبي.
هذه القطعة التالية من UX JS هي إدارة التركيز. أريد تسهيل عملية الفتح والإغلاق، لذلك أنتظر إلى أن ينتهي شريط التنقّل الجانبي من عملية انتقال من نوع ما، ثم أتحقّق منه مقارنةً بملف هَشٍ لعنوان URL لتحديد ما إذا كان مفتوحًا أو مغلقًا. بعد ذلك، أستخدِم JavaScript لضبط التركيز على الزر المكمل للزر الذي ضغط عليه المستخدم للتو.
أضِف مقتطف JavaScript التالي إلى js/index.js
:
const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');
sidenav.addEventListener('transitionend', e => {
if (e.propertyName !== 'transform') {
return;
}
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? closenav.focus()
: opennav.focus();
});
جرّبه الآن
- لمعاينة الموقع الإلكتروني، اضغط على عرض التطبيق. ثم اضغط على ملء الشاشة .
الخاتمة
هذه هي المتطلّبات التي كانت لديّ بشأن المكوّن. يمكنك الاستفادة من هذه الميزة وتطويرها، واستخدام حالة JavaScript بدلاً من عنوان URL، وبشكل عام، تخصيصها بما يناسبك. هناك دائمًا المزيد من المعلومات التي يمكن إضافتها أو المزيد من حالات الاستخدام التي يمكن تغطيتها.
افتح css/brandnav.css
للاطّلاع على الأنماط غير المرتبطة بالتنسيق التي طبّقتها على
هذا المكوّن. لم أعتقد أنّ ذلك مهم لمجموعة الميزات التي كنت أركز عليها، وكنت
أتمنى أن يؤدي فصل الأنماط عن التنسيق إلى تشجيع المستخدمين على النسخ واللصق. قد يكون هناك
مزيد من المعلومات المفيدة لك.
كيف يمكنك إنشاء مكونات قائمة جانبية سريعة الاستجابة للانزلاق للخارج؟ هل سبق لك استخدام أكثر من جهاز واحد، مثل جهاز على كلا الجانبين؟ يسرّني عرض الحلّ الذي وجدته في فيديو على YouTube. يُرجى مراسلتي على Twitter أو نشر تعليق على YouTube يتضمّن الرمز، ما سيساعد الجميع في حلّ المشكلة.