إنشاء مكوِّن القصص

نظرة عامة أساسية حول كيفية إنشاء تجربة مشابهة لـ "قصص Instagram" على الويب

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

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

إذا كنت تفضّل الحصول على عرض توضيحي عملي حول كيفية إنشاء مكوّن "القصص" بنفسك، يمكنك الاطّلاع على الدرس التطبيقي حول مكوّن "القصص".

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

نظرة عامة

من الأمثلة الشائعة على تجربة المستخدم في "القصص"، "قصص Snapchat" و"قصص Instagram" (بالإضافة إلى "الرسائل السريعة"). بشكل عام، القصص هي نمط مخصّص للأجهزة الجوّالة فقط، ويعتمد على النقر للتنقل بين اشتراكات متعددة. على سبيل المثال، على Instagram، يفتح المستخدمون قصة أحد الأصدقاء ويتصفّحون الصور فيها. ويتم ذلك عادةً مع عدد كبير من الأصدقاء في الوقت نفسه. من خلال النقر على الجانب الأيسر من الجهاز، يمكن للمستخدم الانتقال إلى قصة صديقه التالية. من خلال التمرير سريعًا لليسار، يمكن للمستخدم الانتقال إلى صديق آخر. يشبه مكوّن "القصة" إلى حد كبير لوحة العرض الدوّارة، ولكنّه يتيح التنقّل في مصفوفة متعدّدة الأبعاد بدلاً من مصفوفة أحادية الأبعاد. يبدو الأمر وكأنّ هناك لوحة عرض دوّارة داخل كل لوحة عرض دوّارة. 🤯

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

اختيار الأدوات المناسبة للوظيفة

بشكل عام، وجدتُ أنّ إنشاء هذا المكوّن كان بسيطًا جدًا، وذلك بفضل بعض الميزات المهمة في منصة الويب. لنتعرّف عليها.

شبكة CSS

لم يكن تصميمنا صعبًا على CSS Grid، إذ إنّه يتضمّن بعض الطرق الفعّالة لتنظيم المحتوى.

تنسيق الأصدقاء

إنّ أداة التغليف الأساسية .stories هي عبارة عن عرض أفقي قابل للتمرير مع إعطاء الأولوية للأجهزة الجوّالة:

.stories {
  inline-size: 100vw;
  block-size: 100vh;

  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;

  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
  max-inline-size: 480px;
  max-block-size: 848px;
}
استخدام وضع الجهاز في "أدوات مطوّري البرامج في Chrome" لتمييز الأعمدة التي تم إنشاؤها بواسطة Grid

إليك تفاصيل تنسيق grid:

  • نملأ إطار العرض على الأجهزة الجوّالة بشكلٍ صريح باستخدام 100vh و100vw ونحدّ من الحجم على أجهزة الكمبيوتر.
  • يفصل / بين نماذج الصفوف والأعمدة
  • تتم ترجمة auto-flow إلى grid-auto-flow: column
  • نموذج التدفق التلقائي هو 100%، وهو في هذه الحالة أيًّا كان عرض نافذة التمرير

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

التجميع

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

باستخدام شبكة CSS، يمكننا تحديد شبكة ذات خلية واحدة (أي مربّع)، حيث تتشارك الصفوف والأعمدة في اسم مستعار ([story])، ثم يتم تعيين كل عنصر فرعي إلى مساحة الخلية الواحدة التي تحمل الاسم المستعار:

.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.story {
  grid-area: story;
  background-size: cover;
  
}

يمنح ذلك رمز HTML التحكّم في ترتيب التراص ويحافظ أيضًا على تدفّق جميع العناصر. لاحظ كيف لم نكن بحاجة إلى إجراء أي شيء بشأن تحديد موضع absolute أو z-index، ولم نكن بحاجة إلى وضع علامة صح على height: 100% أو width: 100%. حدّدت شبكة العنصر الرئيسي حجم إطار عرض صورة المقالة، لذا لم يكن من الضروري أن يتم توجيه أي من مكوّنات المقالة هذه لملء إطار العرض.

نقاط الالتقاط عند التمرير في CSS

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

التمرير الأفقي بدون أنماط scroll-snap-points وبأنماط scroll-snap-points وبدونها، يمكن للمستخدمين التمرير بحرية كالمعتاد. باستخدام هذه الميزة، يتوقف المتصفّح مؤقتًا عند كل عنصر.
عنصر رئيسي
.stories {
  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
يحدّد العنصر الأصل الذي يتضمّن ميزة تجاوز حد التمرير سلوك المحاذاة.
طفل
.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
يوافق الأطفال على أن يكونوا هدفًا للقطات.

اخترتُ "نقاط الالتقاط أثناء التمرير" لعدة أسباب:

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

التوافق مع جميع المتصفّحات

لقد اختبرنا هذه الميزة على متصفّحات Opera وFirefox وSafari وChrome، بالإضافة إلى نظامَي التشغيل Android وiOS. في ما يلي ملخّص موجز عن ميزات الويب التي رصدنا فيها اختلافات في الإمكانات والتوافق.

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

scroll-snap-stop

كانت لوحات العرض الدوّارة من أهم حالات استخدام تجربة المستخدم التي أدّت إلى إنشاء مواصفات CSS Scroll Snap Points. على عكس "قصص Google"، لا تحتاج لوحة العرض الدوّارة دائمًا إلى التوقّف عند كل صورة بعد أن يتفاعل معها المستخدم. قد يكون من المقبول أو المستحسن التنقّل بسرعة بين عناصر منصة العرض الدوّارة. من ناحية أخرى، من الأفضل التنقّل بين القصص بشكل فردي، وهذا بالضبط ما يوفّره scroll-snap-stop.

.user {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

في وقت كتابة هذه المشاركة، لا يتوافق scroll-snap-stop إلا مع المتصفّحات المستندة إلى Chromium. يمكنك الاطّلاع على توافق المتصفّح لمعرفة آخر الأخبار. مع ذلك، لا يشكّل ذلك عائقًا. هذا يعني فقط أنّه على المتصفّحات غير المتوافقة، يمكن للمستخدمين تخطّي صديق عن طريق الخطأ. لذلك، على المستخدمين توخّي المزيد من الحذر، أو علينا كتابة رمز JavaScript للتأكّد من عدم وضع علامة "تمت المشاهدة" على صديق تم تخطّيه.

يمكنك الاطّلاع على مزيد من المعلومات في المواصفات إذا كنت مهتمًا.

overscroll-behavior

هل سبق لك أن كنت تتنقّل في مربّع حوار مشروط ثم بدأت فجأة في التنقّل في المحتوى خلف مربّع الحوار؟ overscroll-behavior يسمح للمطوّر بحصر التمرير وعدم السماح له بالخروج. إنّه مناسب لجميع أنواع المناسبات. يستخدم مكوّن "قصصي" هذه السمة لمنع إجراء المزيد من حركات التمرير السريع والتمرير التي تؤدي إلى الخروج من المكوّن.

.stories {
  overflow-x: auto;
  overscroll-behavior: contain;
}

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

scrollIntoView({behavior: 'smooth'})

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

element.scrollIntoView({
  behavior: 'smooth'
})

كان Safari هو المتصفّح الوحيد الذي لا يتيح استخدام behavior: 'smooth' هنا. يمكنك الاطّلاع على توافق المتصفّح لمعرفة آخر الأخبار.

التدريب العملي

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

ريمكسات من إنشاء المنتدى