إنشاء مكوِّن أشرطة التنقّل

نظرة عامة أساسية حول كيفية إنشاء مكوِّن أشرطة تنقُّل سريع الاستجابة ويسهل الوصول إليه لتنقل المستخدمين في موقعك الإلكتروني.

في هذه المشاركة، أريد مشاركة التفكير حول طريقة لإنشاء مكونات شريط التنقل. جرِّب الإصدار التجريبي.

إصدار تجريبي

في ما يلي إصدار YouTube من هذه المشاركة إذا كنت تفضّل الفيديوهات:

نظرة عامة

يعرض مكوّن أشرطة تنقّل موضع المستخدم في التسلسل الهرمي للموقع الإلكتروني. واسمه من هانسيل وغريتل اللذَين أسقطا أشرطة تنقّل خلفهما في بعض الغابات الداكنة وتمكّنا من العثور على طريق العودة إلى المنزل من خلال تتبُّع فتات اللحم إلى الخلف.

إنّ أشرطة التنقّل في هذه المشاركة ليست أشرطة تنقّل عادية، إنها تشبه شريط التنقّل. وتوفّر هذه الإعلانات وظائف إضافية من خلال إضافة الصفحات التابعة إلى شريط التنقّل مباشرةً باستخدام <select>، ما يتيح الوصول إلى عدّة مستويات.

تجربة المستخدم في الخلفية

في الفيديو التوضيحي للمكونات أعلاه، فئات العناصر النائبة هي أنواع ألعاب الفيديو. يتم إنشاء هذا المسار من خلال الانتقال إلى المسار التالي: home » rpg » indie » on sale، كما هو موضّح أدناه.

ومن المفترض أن يتيح مكوِّن شريط التنقل هذا للمستخدمين إمكانية التنقل خلال التسلسل الهرمي للمعلومات، والقفز بين الفروع واختيار الصفحات بالسرعة والدقة.

هندسة المعلومات

أجد أنه من المفيد التفكير فيما يتعلق بالمجموعات والعناصر.

المجموعات

المجموعة هي مجموعة من الخيارات للاختيار من بينها. من الصفحة الرئيسية للنموذج الأولي لمسار التنقل في هذا المنشور، تشتمل المجموعات على ألعاب FPS وRPG وتقبيل المعارك وزاحف الزنزانات والرياضة والألغاز.

السلع

لعبة الفيديو عبارة عن عنصر، ويمكن أن تكون مجموعة معينة أيضًا عنصرًا إذا كانت تمثل مجموعة أخرى. على سبيل المثال، تُعد ألعاب تقمّص الأدوار عنصرًا ومجموعة صالحة. عندما يكون المنتج عنصرًا، سيظهر المستخدم في صفحة المجموعة هذه. على سبيل المثال، تكون هذه الألعاب في صفحة ألعاب تقمّص الأدوار التي تعرض قائمة بألعاب تقمّص الأدوار، بما في ذلك الفئات الفرعية الإضافية AAA، وألعاب الإندي وبالنشر الذاتي.

في مصطلحات علوم الكمبيوتر، يمثل مكوِّن شريط التنقل هذا مصفوفة متعددة الأبعاد:

const rawBreadcrumbData = {
  "FPS": {...},
  "RPG": {
    "AAA": {...},
    "indie": {
      "new": {...},
      "on sale": {...},
      "under 5": {...},
    },
    "self published": {...},
  },
  "brawler": {...},
  "dungeon crawler": {...},
  "sports": {...},
  "puzzle": {...},
}

سيكون لتطبيقك أو موقع الويب بنية معلومات مخصصة (IA) تنشئ صفيفًا مختلفًا متعدد الأبعاد، ولكن آمل أن مفهوم الصفحات المقصودة للمجموعة واجتياز التسلسل الهرمي يمكن أن يُدخلهما في مسارات التنقل أيضًا.

التنسيقات

Markup

تبدأ المكونات الجيدة بـ HTML المناسب. في هذا القسم التالي، سأتناول خيارات الترميز وكيف تؤثر على المكون العام.

المظهر الداكن والفاتح

<meta name="color-scheme" content="dark light">

تُعلم العلامة الوصفية color-scheme في المقتطف أعلاه المتصفّح بأنّ هذه الصفحة تريد استخدام نمطَي المتصفّح الفاتح والداكن. ولا تتضمن أمثلة أشرطة التنقل أي CSS لمخططات الألوان هذه، وبالتالي ستستخدم أشرطة التنقل الألوان الافتراضية التي يوفرها المتصفح.

<nav class="breadcrumbs" role="navigation"></nav>

من المناسب استخدام العنصر <nav> للتنقل في الموقع الإلكتروني، والذي له دور ARIA ضمني في التنقّل. أثناء إجراء الاختبارات، لاحظت أنّ السمة role قد غيّرت طريقة تفاعل قارئ الشاشة مع العنصر، وتم تعريفها فعليًا بأنّها إمكانية التنقّل، ولذلك اخترت إضافتها.

الرموز

عند تكرار رمز على صفحة، يعني عنصر SVG <use> أنّه يمكنك تحديد path مرة واحدة واستخدامه في جميع مثيلات الرمز. ويمنع ذلك تكرار معلومات المسار نفسها، ما يؤدي إلى مستندات أكبر واحتمالية عدم اتّساق المسار.

لاستخدام هذا الأسلوب، أضِف عنصر SVG مخفيًا إلى الصفحة ولف الرموز في عنصر <symbol> باستخدام معرّف فريد:

<svg style="display: none;">

  <symbol id="icon-home">
    <title>A home icon</title>
    <path d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
  </symbol>

  <symbol id="icon-dropdown-arrow">
    <title>A down arrow</title>
    <path d="M19 9l-7 7-7-7"/>
  </symbol>

</svg>

يقرأ المتصفح تنسيق SVG HTML ويضع معلومات الرمز في الذاكرة ويتابع باقي الصفحة للإشارة إلى المعرّف للاستخدامات الإضافية للرمز، مثل ما يلي:

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-home" />
</svg>

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-dropdown-arrow" />
</svg>

أدوات مطوري البرامج تعرض عنصرًا لاستخدام SVG معروضًا

يمكنك تحديد المحتوى مرة واحدة، واستخدامه قدر ما تشاء، مع الحفاظ على أقل تأثير في أداء الصفحة وتصميم مرن. الإشعار aria-hidden="true" تمت إضافته إلى عنصر SVG. الأيقونات ليست مفيدة لمن يتصفح ولا يسمع سوى المحتوى، إذ يخفيها عن هؤلاء المستخدمين يمنعه من إضافة تشويش غير ضروري.

هذا هو المكان الذي يختلف فيه شريط التنقل التقليدي عن تلك الموجودة في هذا المكون. في العادة، سيكون هذا رابط <a> فقط، لكنني أضفتُ تجربة الاجتياز مع تحديد مقنَّع. وفئة .crumb مسؤولة عن تخطيط الرابط والرمز، في حين تكون .crumbicon مسؤولة عن تكديس الرمز واختيار العنصر معًا. وأطلقتُ عليه اسم "رابط مجزّأ" لأنّ وظيفته تشبه إلى حدّ كبير زر التقسيم، ولكنّها تتعلّق بالتنقل في الصفحة.

<span class="crumb">
  <a href="#sub-collection-b">Category B</a>
  <span class="crumbicon">
    <svg>...</svg>
    <select class="disguised-select" title="Navigate to another category">
      <option>Category A</option>
      <option selected>Category B</option>
      <option>Category C</option>
    </select>
  </span>
</span>

الرابط وبعض الخيارات لا شيء خاص، ولكنها تضيف المزيد من الوظائف إلى مسار التنقل البسيط. إنّ إضافة title إلى العنصر <select> مفيدة لمستخدمي قارئ الشاشة، ما يمنحهم معلومات عن وظيفة الزر. مع ذلك، ستظهر الأداة المساعدة نفسها للآخرين على جهاز iPad، توفر إحدى السمات سياق الزر للعديد من المستخدمين.

لقطة شاشة تعرض عنصر التحديد غير المرئي الذي يتم تمريره فوقه مع ظهور تلميح سياقي له.

زخارف فاصلة

<span class="crumb-separator" aria-hidden="true">→</span>

تعتبر الفواصل اختيارية، حيث إن إضافة واحدة فقط يفيد جدًا (انظر المثال الثالث في الفيديو أعلاه). أُعطي كل aria-hidden="true" بعد ذلك لأنّها زخرفية ولا تحتاج قارئ الشاشة إلى الإفصاح عنها.

وتجعل السمة gap، التي يتم تناولها بعد ذلك، المسافة بين هذه العناصر أمرًا بسيطًا.

الأنماط

نظرًا لأن اللون يستخدم ألوان النظام، فهو في الغالب فجوات وحزم للأنماط!

اتجاه التصميم وتدفقه

أدوات مطوّري البرامج تعرض محاذاة تنقل شريط التنقّل مع ميزة تراكب flexbox

يضبط عنصر التنقل الأساسي nav.breadcrumbs خاصية مخصصة ذات نطاق مخصص للأطفال الذين يستخدمونها، كما ينشئ تنسيقًا أفقياً متحاذيًا رأسيًا. يضمن ذلك محاذاة الفتات والفواصل والأيقونات.

.breadcrumbs {
  --nav-gap: 2ch;

  display: flex;
  align-items: center;
  gap: var(--nav-gap);
  padding: calc(var(--nav-gap) / 2);
}

شريط تنقّل واحد يظهر بشكل عمودي مع تراكبات مرنة.

ينشئ كل .crumb أيضًا تنسيقًا أفقيًا يتم محاذاته عموديًا مع بعض الفجوة، ولكنّه يستهدف بشكل خاص العناصر الثانوية للرابط الخاص به ويحدّد النمط white-space: nowrap. هذا أمر مهم بالنسبة إلى مسارات التنقل المتعددة الكلمات لأننا لا نريدها أن تكون متعددة الأسطر. سنضيف لاحقًا في هذه المشاركة أنماطًا لمعالجة التجاوز الأفقي الذي تسببت فيه هذه السمة white-space.

.crumb {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--nav-gap) / 4);

  & > a {
    white-space: nowrap;

    &[aria-current="page"] {
      font-weight: bold;
    }
  }
}

تمت إضافة aria-current="page" للمساعدة في إبراز رابط الصفحة الحالية عن غيره. لن يكون لدى مستخدمي برامج قراءة الشاشة مؤشر واضح على أن الرابط للصفحة الحالية فحسب، بل صممنا العنصر بشكل مرئي لمساعدة المستخدمين المبصرين في الحصول على تجربة مستخدم مماثلة.

يستخدم المكوِّن .crumbicon الشبكة لتكديس رمز SVG مع عنصر <select> "غير مرئي تقريبًا".

تظهر &quot;Grid Dev Tools&quot; (أدوات مطوري الشبكة) متراكبة على زر حيث تتم تسمية كل من الصف والعمود
بمكدس.

.crumbicon {
  --crumbicon-size: 3ch;

  display: grid;
  grid: [stack] var(--crumbicon-size) / [stack] var(--crumbicon-size);
  place-items: center;

  & > * {
    grid-area: stack;
  }
}

العنصر <select> هو العنصر الأخير في نموذج العناصر في المستند (DOM)، لذا يكون فوق الحزمة، ويكون تفاعليًا. أضِف نمط opacity: .01 بحيث لا يزال العنصر قابلاً للاستخدام، وتكون النتيجة مربّع اختيار يتناسب تمامًا مع شكل الرمز. هذه طريقة لطيفة لتخصيص مظهر عنصر <select> مع الحفاظ على الوظائف المضمَّنة.

.disguised-select {
  inline-size: 100%;
  block-size: 100%;
  opacity: .01;
  font-size: min(100%, 16px); /* Defaults to 16px; fixes iOS zoom */
}

القائمة الكاملة

يجب أن تكون أشرطة التنقل قادرة على تمثيل ممر طويل جدًا. أنا معجب بالسماح بانتقال الأشياء خارج الشاشة أفقيًا، عندما يكون ذلك مناسبًا، وشعرت أن مكون أشرطة التنقل هذا مؤهل جيدًا.

.breadcrumbs {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: calc(var(--nav-gap) / 2);

  & > .crumb:last-of-type {
    scroll-snap-align: end;
  }

  @supports (-webkit-hyphens:none) { & {
    scroll-snap-type: none;
  }}
}

تقوم أنماط التجاوز بإعداد تجربة المستخدم التالية:

  • تمرير أفقي مع احتواء التمرير الزائد.
  • مساحة متروكة للتمرير الأفقي
  • نقطة انطباق واحدة على الجزء الأخير من الكسر وهذا يعني أنّه عند تحميل الصفحة، يتم سرعة تحميل أول كتلة في طريقة العرض.
  • تتم إزالة نقطة الانطباق من Safari، التي تعاني من مشكلة في تركيبات التأثيرات الأفقية والتمرير الأفقية.

الاستعلامات عن الوسائط

من التعديلات الدقيقة لإطارات العرض الأصغر حجمًا إخفاء تصنيف "الصفحة الرئيسية" وإبقاء الرمز فقط:

@media (width <= 480px) {
  .breadcrumbs .home-label {
    display: none;
  }
}

جنبًا إلى جنب مع أشرطة التنقّل مع تصنيف الصفحة الرئيسية أو بدونها، للمقارنة.

تسهيل الاستخدام

الحركة

لا يحتوي هذا المكوِّن على الكثير من الحركة، ولكن من خلال وضع علامة انتقال بعنصر prefers-reduced-motion، يمكننا منع الحركة غير المرغوب فيها.

@media (prefers-reduced-motion: no-preference) {
  .crumbicon {
    transition: box-shadow .2s ease;
  }
}

ولا يلزم تغيير أي من الأنماط الأخرى، فتأثيرات التمرير والتركيز رائعة وذات مغزى بدون استخدام transition، ولكن إذا كانت الحركة جيدة، سنضيف انتقالاً بسيطًا إلى التفاعل.

JavaScript

أولاً، بغض النظر عن نوع جهاز التوجيه الذي تستخدمه في موقعك أو تطبيقك، عندما يغيّر أحد المستخدمين أشرطة التنقّل، يجب تعديل عنوان URL ويعرض الصفحة المناسبة. ثانيًا، لتسوية تجربة المستخدم، تأكَّد من عدم حدوث عمليات انتقال غير متوقعة أثناء تصفُّح المستخدمين لخيارات <select> فقط.

هناك إجراءان مهمّان للغاية لتحسين تجربة المستخدم يجب التعاملهما باستخدام JavaScript: تم تغيير طريقة منع تنشيط حدث تغيير <select> بشكل كبير ومتحمّس.

يجب اتّخاذ إجراءات الوقاية العاجلة بسبب استخدام عنصر <select>. على نظام التشغيل Windows Edge وربما في المتصفِّحات الأخرى أيضًا، يتم تنشيط حدث changed المحدّد أثناء تصفُّح المستخدم للخيارات باستخدام لوحة المفاتيح. لهذا السبب أسمّى الإجراء "حرّيصًا"، لأنّ المستخدم لم يحدّد سوى الخيار المزيّف، مثل التمرير أو التركيز، ولكنّه لم يؤكِّد الخيار باستخدام enter أو click. ويجعل الحدث السريع هذه ميزة تغيير فئة المكون غير متاحة، لأن فتح مربع التحديد وتصفح أحد العناصر ببساطة سيؤدي إلى تنشيط الحدث وتغيير الصفحة، قبل أن يصبح المستخدم جاهزًا.

حدث تغيير أفضل في <select>

const crumbs = document.querySelectorAll('.breadcrumbs select')
const allowedKeys = new Set(['Tab', 'Enter', ' '])
const preventedKeys = new Set(['ArrowUp', 'ArrowDown'])

// watch crumbs for changes,
// ensures it's a full value change, not a user exploring options via keyboard
crumbs.forEach(nav => {
  let ignoreChange = false

  nav.addEventListener('change', e => {
    if (ignoreChange) return
    // it's actually changed!
  })

  nav.addEventListener('keydown', ({ key }) => {
    if (preventedKeys.has(key))
      ignoreChange = true
    else if (allowedKeys.has(key))
      ignoreChange = false
  })
})

تهدف هذه الاستراتيجية إلى مراقبة أحداث لوحة المفاتيح لأسفل في كل عنصر من عناصر <select> وتحديد ما إذا كان المفتاح الذي تم الضغط عليه هو تأكيد التنقّل (Tab أو Enter) أو التنقّل المكاني (ArrowUp أو ArrowDown). وباستخدام هذا التحديد، يمكن أن يقرّر المكوِّن الانتظار أو الانتقال عند تنشيط حدث عنصر <select>.

الخلاصة

الآن بعد أن عرفت كيف فعلت ذلك، كيف يمكنك‽ 🙂

دعونا ننويع أساليبنا ونتعلم جميع طرق الإنشاء على الويب. يمكنك إنشاء عرض توضيحي وروابط تغريدات لي وسنضيفها إلى قسم الريمكسات في المنتدى أدناه.

ريمكسات من المنتدى