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

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

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

العرض التوضيحي

إذا كنت تفضّل مشاهدة الفيديوهات، يمكنك الاطّلاع على نسخة من هذه المشاركة على YouTube:

نظرة عامة

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

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

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

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

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

بنية المعلومات

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

المجموعات

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

السلع

لعبة الفيديو هي سلعة، ويمكن أن تكون مجموعة معيّنة أيضًا سلعة إذا كانت represent another collection. على سبيل المثال، 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> فقط، ولكن أضفت تجربة مستخدم للتنقّل باستخدام عنصر select مُخفّى. تتحمّل فئة .crumb مسؤولية عرض الرابط والرمز، بينما تتحمّل فئة .crumbicon مسؤولية تجميع الرمز وأحد عناصرselect معًا. لقد أطلقنا على هذا الرابط اسم "رابط مُقسّم" لأنّ وظائفه مشابهة جدًا لوظائف الزر المُقسّم، ولكنه مخصّص للتنقّل في الصفحة.

<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>

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

لقطة شاشة تظهر فيها الإشارة إلى عنصر الاختيار غير المرئي و
ظهور التلميح السياقي

زخارف الفواصل

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

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

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

الأنماط

وبما أنّ اللون يستخدم ألوان النظام، فإنّه يتضمّن في الغالب فراغات ومجموعات من الأنماط.

اتجاه التنسيق ومساره

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

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

.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> "يكاد يكون غير مرئي".

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

.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: اختيار has changed ومنع بدء حدث <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>.

الخاتمة

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

لننوّع أساليبنا ونتعرّف على جميع الطرق لإنشاء تطبيقات على الويب. أنشئ عرضًا توضيحيًا وأرسِل إلينا رابطًا على Twitter، وسنضيفه إلى قسم الريمكسات التي أنشأها المستخدمون أدناه.

الريمكسات التي أنشأها المستخدمون