بدء استخدام الصور المتحركة المستندة إلى التمرير في CSS

1. قبل البدء

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

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

يعلّمك هذا الدرس التطبيقي كيفية إنشاء صور متحركة تعتمد على التمرير باستخدام CSS. بعد إكمال هذا الدرس التطبيقي، ستصبح على دراية بالعديد من خصائص CSS الجديدة التي تقدّمها هذه الميزة الرائعة، مثل scroll-timeline وview-timeline وanimation-timeline وanimation-range.

ما ستتعرَّف عليه

  • كيفية إنشاء تأثير خلفية متباينة باستخدام مخطط زمني للتمرير في CSS
  • كيفية إنشاء شريط تقدّم من خلال "المخطط الزمني للتمرير" في CSS
  • كيفية إنشاء تأثير كشف صورة باستخدام "عرض المخطط الزمني" في CSS
  • كيفية استهداف أنواع مختلفة من النطاقات في "عرض المخطط الزمني" في خدمة مقارنة الأسعار (CSS)

المتطلبات

إحدى مجموعات الأجهزة التالية:

  • إصدار حديث من Chrome (الإصدار 115 أو إصدار أحدث) على ChromeOS أو macOS أو Windows يتضمّن "ميزات النظام الأساسي التجريبي على الويب" تمّ ضبط العلامة على "مفعَّلة".
  • فهم أساسي لـ HTML
  • الإلمام الأساسي بلغة CSS، وخاصة الرسوم المتحركة في CSS

2. الإعداد

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

  1. افتح علامة تبويب جديدة في المتصفح وانتقِل إلى https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab.
  2. استنساخ المستودع.
  3. افتح الرمز في بيئة التطوير المتكاملة (IDE) التي تفضّلها.
  4. شغِّل npm install لتثبيت الاعتماديات.
  5. شغِّل npm start وانتقِل إلى http://localhost:3000/.
  6. بدلاً من ذلك، إذا لم يكن لديك npm مثبّت، افتح ملف src/index.html في Chrome.

3- التعرّف على المخططات الزمنية للصور المتحركة

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

من خلال الصور المتحركة التي تعتمد على التمرير، يمكنك الوصول إلى نوعين جديدين من المخططات الزمنية:

  • الانتقال للأسفل أو للأعلى في المخطط الزمني
  • عرض المخطط الزمني لمستوى التقدُّم

في CSS، يمكن إرفاق هذه المخطّطات الزمنية بإحدى الصور المتحركة باستخدام السمة animation-timeline. تعرَّف على ما تعنيه هذه المخططات الزمنية الجديدة وأوجه اختلافها عن بعضها البعض.

الانتقال للأسفل أو للأعلى في المخطط الزمني

المخطط الزمني لتقدم التمرير هو مخطط زمني لرسوم متحركة مرتبط بالتقدم في موضع التمرير لحاوية تمرير - يسمى أيضًا شريط التمرير أو شريط التمرير - على محور معين. يحول موضعًا في نطاق تمرير إلى نسبة مئوية من التقدم على طول مخطط زمني.

ويمثل موضع التمرير عند البداية مستوى التقدم 0% ويمثل موضع التمرير في النهاية تقدمًا بنسبة 100%. في التصور التالي، لاحظ أن التقدم يتم احتسابه من 0٪ إلى 100٪ أثناء تمرير أشرطة التمرير لأسفل.

عرض المخطط الزمني لمستوى التقدُّم

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

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

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

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

نطاقات "عرض المخطط الزمني" المحتملة التي يمكنك استهدافها هي cover وcontain وentry وexit وentry-crossing وexit-crossing. سيتم شرح هذه النطاقات لاحقًا في هذا الدرس التطبيقي حول الترميز، ولكن إذا كنت متحمّسًا لمعرفة المزيد، يمكنك استخدام الأداة المتوفرة على الرابط https://goo.gle/view-timeline-range-tool لمعرفة ما يمثله كل نطاق.

4. إنشاء تأثير خلفية متناظرة

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

لتنفيذ ذلك، هناك خطوتان يجب اتخاذه:

  1. إنشاء رسم متحرك يؤدي إلى تحريك موضع صورة الخلفية.
  2. قم بربط الحركة بتقدم التمرير في المستند.

إنشاء الصورة المتحركة

  1. لإنشاء صورة متحركة، استخدِم مجموعة منتظمة من الإطارات الرئيسية. وفي هذا الموضع، حرِّك موضع الخلفية من 0% عموديًا إلى 100%:

src/styles.css

@keyframes move-background {
  from {
    background-position: 50% 0%;
  }
  to {
    background-position: 50% 100%;
  }
}
  1. أرفق الآن هذه الإطارات الرئيسية بعنصر النص الأساسي:

src/styles.css

body {
  animation: 1s linear move-background;
}

باستخدام هذا الرمز، تتم إضافة الحركة move-background إلى العنصر الأساسي. تم ضبط السمة animation-duration على ثانية واحدة، ويتم استخدام إرخاء linear.

إنّ أسهل طريقة لإنشاء مخطط تقدّم التمرير هو استخدام الدالة scroll(). يؤدي ذلك إلى إنشاء "المخطط الزمني لمستوى تقدُّم الانتقال" مع إخفاء الهوية، ويمكنك ضبطه كقيمة للسمة animation-timeline.

تقبل الدالة scroll() الوسيطة <scroller> والوسيطة <axis>.

في ما يلي القيم المقبولة للوسيطة <scroller>:

  • nearest لاستخدام أقرب حاوية تمرير للصفحة الأصل (تلقائيًا)
  • root لاستخدام إطار عرض المستند كحاوية تمرير.
  • self تستخدم العنصر نفسه كحاوية تمرير.

في ما يلي القيم المقبولة للوسيطة <axis>:

  • block تستخدم مقياس التقدم على طول محور القالب لحاوية التمرير (الإعداد التلقائي).
  • inline تستخدم مقياس التقدم على طول المحور المضمَّن لحاوية التمرير.
  • y تستخدم مقياس التقدم على طول المحور ص لحاوية التمرير.
  • x تستخدم قياس التقدم على طول المحور x لحاوية التمرير.

لربط الصورة المتحركة بأداة التمرير الجذر على محور الحظر، تكون القيمتان المطلوب تمريرهما إلى scroll() هما root وblock. بتجميع، القيمة هي scroll(root block).

  • ضبط scroll(root block) كقيمة للسمة animation-timeline في النص الأساسي
  • علاوة على ذلك، بما أنّ السمة animation-duration التي يتم التعبير عنها بالثواني غير مفهومة، يمكنك ضبط المدة على auto. إذا لم تحدّد قيمة animation-duration، سيتم ضبط القيمة التلقائية على auto.

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(root block);
}

بما أنّ شريط التمرير الجذر هو أيضًا أقرب شريط تمرير رئيسي للعنصر الأساسي، يمكنك أيضًا استخدام القيمة nearest على النحو التالي:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(nearest block);
}

وبما أنّ nearest وblock هما القيمتان التلقائيتان، يمكنك حتى اختيار حذفهما. في هذه الحالة، يمكن تبسيط الرمز إلى ما يلي:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll();
}

التحقق من التغييرات

إذا سارت الأمور على ما يرام، من المفترض أن يكون لديك الآن التالي:

وإذا لم يكن كذلك، يمكنك الاطّلاع على فرع solution-step-1 من الرمز.

5- إنشاء شريط تقدّم لمعرض الصور

توجد في الصفحة عرض دوار أفقيًا يحتاج إلى شريط تقدم للإشارة إلى الصورة التي تعرضها حاليًا.

يبدو ترميز لوحة العرض الدوّارة كما يلي:

src/index.html

<div class="gallery">
  <div class="gallery__scrollcontainer" style="--num-images: 3;">
    <div class="gallery__progress"></div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
  </div>
</div>

الإطارات الرئيسية لشريط التقدم جاهزة بالفعل وتبدو على النحو التالي:

src/styles.css

@keyframes adjust-progress {
  from {
    transform: scaleX(calc(1 / var(--num-images)));
  }
  to {
    transform: scaleX(1);
  }
}

يجب إرفاق هذه الحركة بملفعنصر gallery__progress مع مخطط زمني لتقدّم الانتقال للأعلى أو للأسفل كما هو موضّح في الخطوة السابقة، يمكنك تحقيق ذلك من خلال إنشاء "المخطط الزمني لمستوى تقدّم التمرير" بدون الكشف عن هويتك باستخدام الوظيفة scroll():

src/styles.css

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  animation-timeline: scroll(nearest inline);
}

إنّ هذا الرمز قد يبدو مناسبًا، لكنّه لا يرجع إلى طريقة عمل عمليات البحث التلقائي في حاويات التمرير باستخدام nearest. عند البحث عن أقرب شريط تمرير، لن يأخذ العنصر في الاعتبار سوى العناصر التي يمكن أن تؤثر في موضعه. نظرًا لأن .gallery__progress هو موضع مؤكد، فإن العنصر الرئيسي الأول الذي سيحدد موضعه هو العنصر .gallery كما تم تطبيق position: relative. وهذا يعني أنّ عنصر .gallery__scrollcontainer، وهو شريط التمرير الذي يجب استهدافه، لا يؤخذ في الاعتبار على الإطلاق خلال هذا البحث التلقائي.

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

لإنشاء "المخطط الزمني لمستوى تقدم التمرير" على أحد العناصر، اضبط سمة CSS scroll-timeline-name في حاوية التمرير على قيمة تعجبك. يجب أن تبدأ القيمة بـ --.

بما أنّه يمكن تمرير المعرض أفقيًا، عليك أيضًا ضبط السمة scroll-timeline-axis. القيم المسموح بها هي نفس وسيطة <axis> لـ scroll().

أخيرًا، لربط الصورة المتحركة بالمخطط الزمني لمستوى تقدُّم الانتقال، اضبط السمة animation-timeline على العنصر الذي يجب تحريكه بالقيمة نفسها المُستخدَمة في المعرِّف المستخدَم في scroll-timeline-name.

  • يمكنك تغيير الملف styles.css لتضمين ما يلي:

src/styles.css

.gallery__scrollcontainer {
  /* Create the gallery-is-scrolling timeline */
  scroll-timeline-name: --gallery-is-scrolling;
  scroll-timeline-axis: inline;
}

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  /* Set gallery-is-scrolling as the timeline */
  animation-timeline: --gallery-is-scrolling;
}

التحقق من التغييرات

إذا سارت الأمور على ما يرام، من المفترض أن يكون لديك الآن التالي:

وإذا لم يكن كذلك، يمكنك الاطّلاع على فرع solution-step-2 من الرمز.

6- أضِف تأثيرات حركية إلى صور المعرض عند الدخول إلى شريط التمرير والخروج منه

إعداد مخطط زمني مع إخفاء الهوية لعرض مستوى التقدّم

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

لإنشاء "عرض مخطط زمني للتقدّم"، يمكنك استخدام الدالة "view()". الوسيطات المقبولة هي <axis> و<view-timeline-inset>.

  • يتطابق <axis> مع المخطط الزمني لتقدم التمرير ويحدد المحور الذي يجب تتبعه.
  • وباستخدام <view-timeline-inset>، يمكنك تحديد إزاحة (موجب أو سالب) لضبط الحدود إذا كان أحد العناصر معروضًا أو لا.
  • الإطارات الرئيسية موجودة بالفعل في مكانها، لذا ما عليك سوى إرفاقها. ولإجراء ذلك، أنشِئ "عرض المخطط الزمني لمستوى التقدّم" في كل عنصر من عناصر ".gallery__entry".

src/styles.css

@keyframes animate-in {
  from {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  to {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
}

تحديد النطاق الزمني لعرض مستوى التقدّم

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

وذلك لأنّ النطاق التلقائي لعرض "المخطط الزمني للتقدّم" هو النطاق الكامل. ويُعرف ذلك باسم النطاق cover.

  1. لاستهداف النطاق entry فقط من الموضوع، استخدِم سمة CSS animation-range لتحديد وقت تشغيل الصورة المتحركة.

src/styles.css

.gallery__entry {
  animation: linear fade-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry 0% entry 100%;
}

يتم تشغيل الصورة المتحركة الآن من entry 0% (على وشك دخول الموضوع في شريط التمرير) إلى entry 100% (إدخال الموضوع إلى شريط التمرير بالكامل).

في ما يلي نطاقات المخطط الزمني المحتملة للعرض:

  • cover يمثل هذا القسم النطاق الكامل للمخطط الزمني لتقدم العرض.
  • entry يمثل هذا الحقل النطاق الذي يدخل خلاله المربع الأساسي نطاق مستوى رؤية تقدم العرض.
  • exit يمثل هذا الحقل النطاق الذي يخرج خلاله المربع الأساسي من نطاق مستوى رؤية تقدم العرض.
  • entry-crossing يمثل النطاق الذي يتخطى فيه المربع الرئيسي حافة حدود النهاية.
  • exit-crossing يمثل النطاق الذي يتخطى فيه المربع الرئيسي حافة حد البداية.
  • contain يمثّل هذا الحقل النطاق الذي يكون فيه المربّع الأساسي مضمَّنًا بشكل كامل في نطاق ظهور تقدّم العرض ضمن شريط التمرير أو يشمله بالكامل. ويعتمد ذلك على ما إذا كان العنصر أطول أو أقصر من شريط التمرير.

يمكنك استخدام الأداة المتوفرة على https://goo.gle/view-timeline-range-tool للاطّلاع على ما يمثله كل نطاق ومدى تأثير النسب المئوية في موضعَي البداية والنهاية.

  1. بما أنّ نطاقَي البداية والنهاية متطابقَين هنا ويتم استخدام قيم الإزاحة التلقائية، يمكنك تبسيط animation-range إلى اسم نطاق واحد للصور المتحركة:

src/styles.css

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry;
}
  • لإظهار الصور المتحركة عند خروجها من شريط التمرير، يمكنك أن تفعل الشيء نفسه مع الرسوم المتحركة المتحركة ولكن مع استهداف نطاق مختلف.

src/styles.css

@keyframes animate-out {
  from {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  to {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in, linear animate-out;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry, exit;
}

سيتم تطبيق الإطارات الرئيسية animate-in على نطاق entry وanimate-out من الإطارات الرئيسية على نطاق exit.

التحقق من التغييرات

إذا سارت الأمور على ما يرام، من المفترض أن يكون لديك الآن التالي:

وإذا لم يكن كذلك، يمكنك الاطّلاع على فرع solution-step-3 من الرمز.

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

حالة مجموعة واحدة من الإطارات الرئيسية

بدلاً من إرفاق رسمين متحركين لنطاقات مختلفة، يمكن إنشاء مجموعة واحدة من الإطارات الرئيسية التي تحتوي بالفعل على معلومات النطاق.

ويظهر شكل الإطارات الرئيسية على النحو التالي:

@keyframes keyframes-name {
  range-name range-offset {
    ...
  }
  range-name range-offset {
    ...
  }
}
  1. اجمع بين الإطارات الرئيسية للتلاشي والتلاشي على النحو التالي:

src/styles.css

@keyframes animate-in-and-out {
  entry 0% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  entry 90% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }

  exit 10% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  exit 100% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}
  1. عند عرض معلومات النطاق في الإطارات الرئيسية، لن تحتاج إلى تحديد animation-range بشكلٍ منفصل بعد ذلك. أرفق الإطارات الرئيسية كسمة animation.

src/styles.css

.gallery__entry {
  animation: linear animate-in-and-out both;
  animation-duration: auto;
  animation-timeline: view(inline);
}

التحقق من التغييرات

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

8. تهانينا!

لقد أكملت هذا الدرس التطبيقي حول الترميز وأصبحت الآن تعرف كيفية إنشاء Scroll Progress "المخططات الزمنية لمستوى التقدّم" و"عرض المخططات الزمنية للتقدّم" في CSS.

مزيد من المعلومات

المصادر: