آموزش ساخت انیمیشنهای اسکرول (Scroll-driven) با استانداردهای CSS 2026
رفیق برنامهنویس، آمادهای تا وبسایتها رو با جادوی اسکرول زنده کنی؟ دنیای انیمیشنهای اسکرولمحور با CSS 2026 فراتر از تصور ماست.
اینجا قراره قدم به قدم یاد بگیریم چطور از نهایت قدرت CSS برای ساخت تجربههای کاربری شگفتانگیز استفاده کنیم.
حین خوندن مقاله، اگر به ابزار یا کد آمادهای نیاز داشتی، یادت نره یه سر به
فروشگاه ابزارهای ما
بزنی؛ کلی چیز به دردبخور برات داریم!
✨ نقشه راه انیمیشنهای اسکرولمحور CSS 2026 در یک نگاه ✨
• مقدمه
- 🚀 چرا Scroll-driven؟
- 💡 مزایای رویکرد جدید
- 🎯 هدف مقاله
• مفاهیم کلیدی
- ⏳ `scroll-timeline` (زمانبندی)
- 👁️ `view-timeline` (محدوده دید)
- ⚙️ `animation-timeline` (اتصال)
• پیادهسازی
- 📝 CSS `keyframes`
- 🔗 اتصال Timeline
- 📐 تنظیم offsetها
• نکات پیشرفته
- ⚡️ بهینهسازی عملکرد
- 🌐 سازگاری مرورگر
- 🛠️ عیبیابی رایج
تماس با ما:
09202232789
مقدمه: چرا انیمیشنهای اسکرولمحور (Scroll-driven) اینقدر مهم شدن؟
تا همین چند وقت پیش، ساخت انیمیشنهایی که با حرکت اسکرول کاربر هماهنگ باشن، دردسرای خودش رو داشت. باید کلی جاوااسکریپت مینوشتیم، Event Listener اضافه میکردیم و دائم موقعیت اسکرول رو چک میکردیم. این کار نه تنها کد رو پیچیده میکرد، بلکه معمولاً به خاطر حجم بالای پردازش، پرفورمنس خوبی هم نداشت. اما حالا، با پیشرفتهای جدید توی CSS و استانداردهای 2026، داستان کاملاً عوض شده.
انیمیشنهای اسکرولمحور دیگه فقط یه حرکت لوکس نیستن؛ تبدیل شدن به یه بخش جدانشدنی از تجربه کاربری مدرن. اونا میتونن حس عمیقتری از تعامل رو به کاربر دن، روایت داستان یک برند رو تقویت کنن و حتی راهنمای بصری برای محتوای تو باشن. با اومدن قابلیتهای جدید CSS، این نوع انیمیشنها رو میتونیم مستقیم توی شیوه نامه (stylesheet) تعریف کنیم که هم سادهتره و هم پرفورمنس بهتری داره. بیایید غرق بشیم و ببینیم چطور این کار شدنیه. برای یادگیری بیشتر و عمیقتر، میتونی به صفحه اصلی ما سر بزنی.
مفاهیم بنیادی: `scroll-timeline` و `view-timeline` در قلب CSS 2026
قبل از اینکه بریم سراغ کدنویسی، لازمه دو مفهوم اساسی رو خوب درک کنیم: `scroll-timeline` و `view-timeline`. این دو ویژگی، موتور محرک انیمیشنهای اسکرولمحور ما هستن و به ما اجازه میدن تا زمانبندی انیمیشن رو به جای زمان، به پیشرفت اسکرول یا ورود یک عنصر به محدوده دید کاربر متصل کنیم.
1. `scroll-timeline`: زمانبندی با حرکت اسکرول
این ویژگی بهت اجازه میده تا پیشرفت یک انیمیشن رو به میزان اسکرول یک کانتینر خاص (یا خود صفحه) گره بزنی. از 0% (ابتدای اسکرول) تا 100% (انتهای اسکرول)، انیمیشن همزمان با حرکت کاربر اجرا میشه.
2. `view-timeline`: زمانبندی با محدوده دید
برخلاف `scroll-timeline` که کل مسیر اسکرول رو در نظر میگیره، `view-timeline` بر اساس ورود و خروج یک عنصر خاص به محدوده دید کاربر (Viewport) عمل میکنه. وقتی یه المان شروع به ظاهر شدن در صفحه میکنه تا وقتی که کاملاً از دید خارج میشه، انیمیشن فعال میشه. این رویکرد برای افکتهای Parallax یا reveal کردن محتوا عالیه.
3. `animation-timeline`: اتصال نهایی
این خاصیت، دقیقاً همون چیزیه که انیمیشن (تعریف شده با `animation` یا `@keyframes`) رو به `scroll-timeline` یا `view-timeline` که قبلاً ساختیم، متصل میکنه.
| ویژگی | توضیح |
|---|---|
| `scroll-timeline` | پیشرفت انیمیشن بر اساس اسکرول کل کانتینر. از 0% تا 100% مسیر اسکرول. |
| `view-timeline` | پیشرفت انیمیشن بر اساس ورود یا خروج یک عنصر خاص از محدوده دید کاربر. |
| `animation-timeline` | ویژگیای برای اتصال انیمیشنهای `@keyframes` به یک `timeline` (اسکرول یا ویو). |
گام به گام: ساخت اولین انیمیشن اسکرولمحور با `view-timeline`
بریم سراغ یه مثال عملی. میخوایم یه کارتی داشته باشیم که وقتی وارد محدوده دید کاربر میشه، از پایین به بالا ظاهر بشه و محو بودنش هم از بین بره (fade-in up effect).
مرحله 1: ساختار HTML
یه ساختار ساده داریم، یه کانتینر اصلی و چند تا کارت که قراره با اسکرول متحرک بشن.
<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>انیمیشن اسکرول-محور</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header style="height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #3498db; color: white; font-size: 2em;">
به صفحه خوش آمدید! اسکرول کنید...
</header>
<div class="container">
<div class="card">محتوای کارت 1</div>
<div class="card">محتوای کارت 2</div>
<div class="card">محتوای کارت 3</div>
<div class="card">محتوای کارت 4</div>
<div class="card">محتوای کارت 5</div>
<div class="card">محتوای کارت 6</div>
</div>
<footer style="height: 50vh; display: flex; align-items: center; justify-content: center; background-color: #333; color: white; font-size: 1.5em;">
پایان محتوا
</footer>
</body>
</html>
مرحله 2: استایلهای پایه CSS
حالا استایلهای اولیه رو برای `body`، `container` و `card` تعریف میکنیم.
/* style.css */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
overflow-x: hidden; /* برای جلوگیری از اسکرول افقی ناخواسته */
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.card {
background-color: white;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
margin: 40px 0;
padding: 30px;
height: 200px; /* برای اینکه به اندازه کافی بلند باشن تا انیمیشن دیده بشه */
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5em;
color: #555;
}
مرحله 3: تعریف `keyframes` برای انیمیشن
حالا انیمیشنی رو که میخوایم اجرا بشه، با `@keyframes` تعریف میکنیم. اینجا اسمش رو میذاریم `fade-in-up-animation`.
/* ادامه style.css */
@keyframes fade-in-up-animation {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
مرحله 4: اتصال انیمیشن به `view-timeline`
اینجا جادوی اصلی اتفاق میافته. برای هر کارت، یه `view-timeline` جداگانه تعریف میکنیم و انیمیشنمون رو بهش وصل میکنیم. این کار باعث میشه انیمیشن هر کارت مستقل از بقیه، فقط زمانی که وارد Viewport کاربر میشه، فعال بشه. این رویکرد به ویژه برای ایجاد حس حرکت تدریجی در یک لیست طولانی، کارآمده و تجربه کاربری رو بهبود میبخشه.
/* ادامه style.css */
.card {
/* ... استایلهای قبلی کارت ... */
/* اول انیمیشن رو در حالت اولیه (قبل از ظاهر شدن) قرار میدیم */
opacity: 0;
transform: translateY(50px);
/* تعریف View Timeline برای هر کارت */
view-timeline-name: --card-reveal;
view-timeline-axis: block; /* جهت اسکرول عمودی */
/* اتصال انیمیشن به Timeline */
animation: fade-in-up-animation linear forwards;
animation-timeline: --card-reveal;
/* این یعنی انیمیشن از وقتی کارت 20% از پایین صفحه وارد Viewport بشه،
تا وقتی که 20% از بالای صفحه از Viewport خارج بشه، اجرا میشه. */
animation-range: entry 20% cover 20%;
}
توضیح `animation-range`: کلید کنترل دقیق
خاصیت `animation-range` فوقالعاده قدرتمنده و به ما اجازه میده تا دقیقاً مشخص کنیم انیمیشن از چه نقطهای و تا چه نقطهای در `timeline` اجرا بشه. مقادیر `entry`، `exit`، `cover` و `contain` برای این کار هستن که هر کدوم میتونن با یک درصد یا طول ترکیب بشن.
- `entry`: نقطه شروع ورود عنصر به محدوده دید (Viewport).
- `exit`: نقطه خروج کامل عنصر از محدوده دید.
- `cover`: تمام محدوده زمانی که عنصر در ویوپورت قرار دارد.
- `contain`: تمام محدوده زمانی که عنصر کاملاً در ویوپورت جای میگیرد.
در مثال بالا، `animation-range: entry 20% cover 20%;` به این معنیه که انیمیشن از زمانی شروع میشه که 20% از پایین کارت وارد Viewport شده باشه (`entry 20%`) و تا زمانی ادامه پیدا میکنه که کارت به طور کامل (100% از خودش) در Viewport قرار بگیره و بعد 20% هم ازش خارج بشه (`cover 20%`). این کنترل دقیق بهت امکان میده افکتهای خلاقانهتری بسازی.
تکنیکهای پیشرفته و بهینهسازی
ساخت انیمیشنهای اسکرولمحور فقط در مورد سینتکس نیست؛ باید حواست به پرفورمنس و تجربه کاربری هم باشه.
1. استفاده از `will-change` (با احتیاط!)
خاصیت `will-change` به مرورگر میگه که یه عنصر قراره تغییر کنه و این امکان رو به مرورگر میده که قبل از وقوع تغییر، بهینهسازیهای لازم رو انجام بده. این میتونه پرفورمنس رو به شدت بهبود ببخشه، مخصوصاً برای انیمیشنهای سنگین. اما حواست باشه، زیادهروی در استفاده ازش میتونه اثر معکوس داشته باشه و منابع سیستم رو الکی اشغال کنه. فقط برای عناصر کلیدی که انیمیشن روشون اجرا میشه، استفاده کن.
.card {
/* ... */
will-change: opacity, transform; /* به مرورگر اطلاع میدهیم این خصوصیات تغییر میکنند */
}
2. بهینهسازی برای موبایل و تبلت و حتی تلویزیون
همونطور که میدونی، وبسایتها باید روی هر دستگاهی عالی به نظر برسن و کار کنن. انیمیشنهای اسکرولمحور هم از این قاعده مستثنی نیستن. مطمئن شو که انیمیشنهات روی صفحه نمایشهای کوچیک (موبایل و تبلت) و حتی بزرگتر (تلویزیون) هم روان و بدون مشکل اجرا میشن. ممکنه نیاز باشه با Media Queryها، سرعت یا شدت انیمیشن رو برای دستگاههای مختلف تنظیم کنی. این موضوع به خصوص برای کاربرانی که از طریق موبایل یا تبلت با تیم فنی تماس میگیرن مهمه.
@media (max-width: 768px) {
.card {
/* شاید انیمیشن روی موبایل با سرعت کمتری اجرا بشه یا افکتش سادهتر بشه */
/* animation-range: entry 10% cover 10%; */
}
}
3. پرهیز از انیمیشنهای بیش از حد
زیبایی در سادگیه. انیمیشنهای زیاد و شلوغ نه تنها پرفورمنس رو پایین میارن، بلکه کاربر رو هم گیج و خسته میکنن. هدف، بهبود تجربه کاربریه، نه آزار دادن اون. از انیمیشنها با هدف و در جای درست استفاده کن.
سازگاری مرورگرها و Fallbackها
انیمیشنهای اسکرولمحور CSS در حال حاضر (اواخر 2024 و 2025) در بیشتر مرورگرهای مدرن مثل Chrome و Edge به خوبی پشتیبانی میشن. فایرفاکس و سافاری هم در حال افزودن پشتیبانی هستن. اما برای سال 2026، انتظار میره که پشتیبانی گستردهتر و کاملتری داشته باشیم. اما همیشه باید برای مرورگرهایی که هنوز این ویژگیها رو ساپورت نمیکنن، یه برنامه جایگزین داشته باشیم.
Fallback با `@supports`
با استفاده از `@supports` میتونیم تشخیص بدیم که مرورگر از ویژگیهای `timeline` پشتیبانی میکنه یا نه، و بر اساس اون، استایلهای متفاوتی اعمال کنیم.
/* Fallback: استایل پیشفرض برای مرورگرهای بدون پشتیبانی */
.card {
opacity: 1; /* کارتها به طور پیشفرض قابل مشاهده باشن */
transform: translateY(0);
}
/* اگر مرورگر از timeline پشتیبانی کنه */
@supports (animation-timeline: auto) {
.card {
opacity: 0; /* در ابتدا مخفی */
transform: translateY(50px); /* کمی به پایین */
view-timeline-name: --card-reveal;
view-timeline-axis: block;
animation: fade-in-up-animation linear forwards;
animation-timeline: --card-reveal;
animation-range: entry 20% cover 20%;
}
}
با این روش، مطمئن میشیم که محتوای تو توی هر مرورگری قابل دسترسه، حتی اگر انیمیشنهاش فعال نباشن.
نکته: برای دسترسی به کدهای آماده بیشتر و اسنیپتهای CSS کاربردی، میتونی از بخش کدهای آماده و اسنیپت ما استفاده کنی.
چالشها و راهحلهای رایج (Troubleshooting)
هیچ وقت فکر نکن اولین باری که کد میزنی، همه چیز بیعیب و نقص کار میکنه! مشکلات تو این راه طبیعیه. بیا چند تا از مشکلات رایج و راهحلهاشون رو بررسی کنیم.
مشکل 1: انیمیشن اجرا نمیشه یا فقط یک بار اجرا میشه
علت احتمالی:
- ممکنه `view-timeline-name` یا `animation-timeline` اشتباه نوشته شده باشه.
- مقادیر `animation-range` بیش از حد محدود یا غلط باشن.
- خاصیت `animation-fill-mode` روی `forwards` تنظیم نشده باشه، که باعث میشه انیمیشن بعد از پایان به حالت اولیه برگرده.
راهحل:
- اسم `timeline` رو دوباره چک کن که دقیقا همونی باشه که تعریف کردی (با `–` شروع بشه).
- مطمئن شو که `animation-fill-mode: forwards;` رو برای انیمیشن فعال کردی تا حالت نهایی انیمیشن حفظ بشه.
- با مقادیر `animation-range` بازی کن. مثلاً `entry 0% cover 100%` رو امتحان کن تا کل مسیر دیده شدن عنصر رو پوشش بده.
مشکل 2: پرفورمنس ضعیف یا کندی در اسکرول
علت احتمالی:
- انیمیشنها روی خاصیتهایی اجرا میشن که مرورگر رو مجبور به بازسازی کامل Layout یا Paint کنه (مثل `width`, `height`, `margin`, `padding`).
- تعداد زیادی انیمیشن همزمان در حال اجراست.
- عدم استفاده بهینه از `will-change`.
راهحل:
- همیشه سعی کن انیمیشنهات رو روی خاصیتهای `transform` (مثل `translate`, `scale`, `rotate`) و `opacity` اجرا کنی. اینها به GPU واگذار میشن و خیلی روانترن.
- تعداد انیمیشنهای همزمان رو به حداقل برسون.
- `will-change: transform, opacity;` رو به المانهای متحرک اضافه کن، اما نه برای همه چیز.
- ابزار Performance در DevTools مرورگر رو باز کن و گلوگاهها رو پیدا کن.
مشکل 3: انیمیشن روی برخی مرورگرها کار نمیکنه
علت احتمالی:
- مرورگر مورد نظر هنوز از Scroll-driven Animations پشتیبانی نمیکنه.
- عدم استفاده از Fallback مناسب.
راهحل:
- از `@supports` استفاده کن تا برای مرورگرهای بدون پشتیبانی، یک استایل جایگزین ارائه بدی (همونطور که بالاتر توضیح دادیم).
- پشتیبانی مرورگرها رو در وبسایتهایی مثل Can I use بررسی کن.
- مطمئن شو که از آخرین نسخه مرورگرها برای تست استفاده میکنی.
نتیجهگیری: آیندهای روشن برای انیمیشنهای وب
انیمیشنهای اسکرولمحور با CSS 2026 یه قدم بزرگ برای توسعهدهندگان وب محسوب میشن. دیگه نیازی به راهحلهای پیچیده جاوااسکریپتی نیست و میتونیم با کد تمیزتر و پرفورمنس بهتر، تجربههای کاربری واقعاً منحصر به فردی بسازیم. این قابلیتها به ما قدرت زیادی برای خلق رابطهای کاربری تعاملی و جذاب میدن. پس بدون معطلی دست به کار شو و این قابلیتهای جدید رو تو پروژههات پیادهسازی کن. فراموش نکن که برای اطلاعات بیشتر و جدیدترین مقالات، همیشه میتونی به وبسایت ما سر بزنی.
پرسشهای متداول (FAQ)
Q: انیمیشنهای اسکرولمحور CSS در چه مرورگرهایی پشتیبانی میشوند؟
A: در حال حاضر (سالهای 2024-2025) مرورگرهای مبتنی بر Chromium مانند Chrome و Edge پشتیبانی خوبی از این ویژگی دارند. انتظار میرود تا سال 2026، پشتیبانی در مرورگرهای Firefox و Safari نیز گسترده و کامل شود. همیشه برای اطمینان بیشتر، Can I use را چک کنید.
Q: تفاوت `scroll-timeline` و `view-timeline` چیست؟
A: `scroll-timeline` پیشرفت انیمیشن را به کل مسیر اسکرول یک کانتینر یا صفحه گره میزند (از 0% تا 100% اسکرول). در مقابل، `view-timeline` پیشرفت انیمیشن را بر اساس ورود یا خروج یک عنصر خاص از محدوده دید کاربر (Viewport) کنترل میکند.
Q: چگونه میتوان پرفورمنس انیمیشنهای اسکرولمحور را بهبود بخشید؟
A: برای بهبود پرفورمنس، سعی کنید انیمیشنها را بر روی ویژگیهای `transform` و `opacity` اعمال کنید، زیرا این ویژگیها توسط GPU شتابدهی میشوند. همچنین، از `will-change: transform, opacity;` با احتیاط استفاده کنید و از انیمیشنهای بیش از حد در یک زمان پرهیز کنید.
Q: آیا برای هر انیمیشن اسکرولمحور نیاز به JavaScript است؟
A: خیر، زیبایی استانداردهای جدید CSS در این است که میتوانید انیمیشنهای اسکرولمحور پیچیده را تنها با استفاده از CSS و بدون نیاز به حتی یک خط JavaScript پیادهسازی کنید، مگر اینکه نیاز به منطق خاص یا تعاملات پیچیدهتری داشته باشید.
// این اسکریپت تنها برای نمایش دکمههای کپی کد در ویرایشگرهای بلوک استفاده میشود و بخشی از محتوای اصلی مقاله نیست.
// در محیط واقعی، این دکمهها باید توسط سیستم CMS یا پلاگین مربوطه اضافه شوند.
document.addEventListener(‘DOMContentLoaded’, () => {
const codeBlocks = document.querySelectorAll(‘pre’);
codeBlocks.forEach(block => {
const wrapper = block.parentElement;
if (wrapper && wrapper.style.position === ‘relative’) {
const copyButtonText = wrapper.querySelector(‘span:last-child’);
if (copyButtonText && copyButtonText.textContent === ‘[دکمه کپی کد]’) {
const button = document.createElement(‘button’);
button.textContent = ‘کپی کد’;
button.style.cssText = `
position: absolute;
top: 10px;
left: 10px;
background-color: #007bff;
color: white;
border: none;
padding: 8px 12px;
border-radius: 5px;
cursor: pointer;
font-size: 0.8em;
transition: background-color 0.3s ease;
font-family: ‘Vazirmatn’, sans-serif;
`;
button.onmouseover = () => button.style.backgroundColor = ‘#0056b3’;
button.onmouseout = () => button.style.backgroundColor = ‘#007bff’;
button.onclick = () => {
const codeToCopy = block.textContent;
navigator.clipboard.writeText(codeToCopy).then(() => {
button.textContent = ‘کپی شد!’;
setTimeout(() => {
button.textContent = ‘کپی کد’;
}, 2000);
}).catch(err => {
console.error(‘Failed to copy text: ‘, err);
button.textContent = ‘خطا در کپی!’;
});
};
wrapper.insertBefore(button, block);
copyButtonText.remove(); // Remove the placeholder text
}
}
});
});