Driven · فصل ٤

Scroll Driven و Zoom و Parallax — الحركة ماشية مع الـ scroll

animation-timeline · scroll() · view() · animation-range · @supports fallback
🎯 الهدف: تربط أي CSS animation بمكان الـ scroll من غير JavaScript، وتعمل progress bar و zoom و parallax.

الفكرة: الـ timeline بقى الـ scroll

الـ CSS animation العادية ماشية بالوقت: ثانيتين من 0% لـ 100%. الـ scroll-driven animation نفس الـ keyframes بالظبط، بس الـ 0% هو أول الـ scroll، والـ 100% هو آخره.

📜 scroll()

التقدّم = مكانك في الـ scroller كله. من 0 لما تبقى فوق خالص، لـ 1 لما توصل لتحت خالص.

👁️ view()

التقدّم = مكان عنصر معيّن وهو بيعدّي في الشاشة: من أول ما يدخل لحد ما يخرج.

Scroll Driven: progress bar

الشريط بيتملا مع القراية

متصفحك لسه مش بيدعم scroll-driven animations، فالديمو ثابت. جرّبه على Chrome أو Edge أو Safari حديث.

progress.css
.progress {  position: fixed;  inset: 0 0 auto;  height: 4px;  background: #6c4bff;  transform-origin: right; /* RTL: يتملا من اليمين */  animation: grow linear both;  animation-timeline: scroll(root block);}@keyframes grow {  from { transform: scaleX(0); }  to { transform: scaleX(1); }}

scroll(root block) معناها: الـ scroller هو الصفحة (root)، والمحور الرأسي (block). جوه container بيعمل scroll، استخدم scroll() من غير parameters، فياخد أقرب scroller.

Zoom on scroll: الصورة تكبر وهي داخلة

الصورة بتكبر وهي بتعدّي

متصفحك لسه مش بيدعم scroll-driven animations، فالديمو ثابت. جرّبه على Chrome أو Edge أو Safari حديث.

zoom.css
.photo {  animation: zoom-in linear both;  animation-timeline: view();  animation-range: entry 0% cover 50%; /* من أول ما يدخل لحد ما يوصل نص الشاشة */}@keyframes zoom-in {  from { transform: scale(0.55); opacity: 0.35; }  to { transform: scale(1); opacity: 1; }}
الـ rangeمعناه
entryمن أول ما العنصر يلمس الشاشة لحد ما يدخل كله
exitمن أول ما يبدأ يخرج لحد ما يختفي
coverمن أول ما يلمس لحد ما يختفي خالص
containالفترة اللي هو فيها جوه الشاشة كله (أو مالي الشاشة كلها لو أطول منها)

Parallax: الخلفية أبطأ

الشمس والجبال بيتحركوا بسرعات مختلفة
عنوان الصفحة

متصفحك لسه مش بيدعم scroll-driven animations، فالديمو ثابت. جرّبه على Chrome أو Edge أو Safari حديث.

الإحساس بالعمق جاي من إن الطبقات البعيدة بتتحرك أبطأ. في الديمو: المحتوى بيطلع لفوق بسرعة الـ scroll، والجبال بتنزل شوية (فتبان أبطأ)، والشمس بتنزل أكتر (فتبان أبعد).

parallax.css
.hero { overflow: clip; } /* مش hidden، شوف التحذير تحت */.hero .far,.hero .near {  animation: linear both;  animation-timeline: scroll(root);  animation-range: 0 400px; /* أول 400px scroll بس، وده طول الـ hero */}.hero .far { animation-name: far; }.hero .near { animation-name: near; }@keyframes far { to { transform: translateY(240px); } }@keyframes near { to { transform: translateY(100px); } }

لو المتصفح مش بيدعم

الـ scroll-driven animations مدعومة في Chrome و Edge من 2023، وفي Safari الحديث. أما Firefox فكان لسه وراء flag آخر مرة راجعت، فشوف caniuse قبل ما تعتمد عليه. لفّها في @supports عشان المتصفح القديم يشوف الحالة النهائية الثابتة:

@supports (animation-timeline: scroll()) {  .progress { animation: grow linear both; animation-timeline: scroll(root block); }}

ولو لازم يشتغل في كل حتة، في polyfill رسمي من نفس الفريق (scroll-timeline polyfill)، أو ترجع لـ IntersectionObserver مع progress تقريبي.

خلّصت الفصل لما

🧠 اختبر نفسك
١) عايز animation تشتغل وعنصر معيّن بيعدّي الشاشة. scroll ولا view؟
view() لأن التقدّم محسوب على العنصر نفسه.
٢) محتاج JS للـ progress bar؟
لأ، animation-timeline: scroll() بيعمله بـ CSS بس.
٣) ليه linear مع الـ scroll؟
لأن الـ easing بيتطبق على المسافة، فـ ease بيحسّس إن الحركة مش متناسقة.