پارالاکس و لایه‌بندی برای ساخت عمق در سایت اسکرولی

پارالاکس، لایه‌بندی و تایپوگرافی متحرک

⏱ زمان مطالعه: حدود ۸ دقیقه

در درس قبل با پین و اسکراب اسکلت حرکتی صفحه را ساختیم. حالا وقت جزئیاتی است که تفاوت بین «یک صفحهٔ متحرک» و «یک صفحهٔ سینمایی» را می‌سازد: عمق و شخصیت.

عمق را با پارالاکس و لایه‌بندی می‌سازیم، شخصیت را با تایپوگرافی متحرک. هر دو تکنیک‌هایی هستند که اگر درست به‌کار بروند نامرئی‌اند و اگر غلط به‌کار بروند، اولین چیزی هستند که چشم را می‌زنند.

پارالاکس و لایه‌بندی برای ساخت عمق در سایت اسکرولی

پارالاکس: چرا مغز ما فریب می‌خورد

وقتی از پنجرهٔ ماشین بیرون را نگاه می‌کنی، درخت‌های نزدیک سریع رد می‌شوند و کوه‌های دور تقریباً ثابت‌اند. مغز از همین اختلاف سرعت، فاصله را حدس می‌زند. پارالاکس در وب دقیقاً همین ترفند است: لایه‌های پس‌زمینه کندتر از پیش‌زمینه حرکت می‌کنند و مغز، عمق را می‌سازد.

پیاده‌سازی پایه‌اش شگفت‌آور ساده است:

gsap.utils.toArray('[data-speed]').forEach(el => {
  const speed = parseFloat(el.dataset.speed);   // مثلاً 0.5 یا 1.3
  gsap.to(el, {
    yPercent: (1 - speed) * 40,
    ease: 'none',
    scrollTrigger: {
      trigger: el.closest('.scene'),
      start: 'top bottom',
      end: 'bottom top',
      scrub: true,
    }
  });
});

و در HTML:

<div class="layer layer--sky"   data-speed="0.3"></div>
<div class="layer layer--hills" data-speed="0.6"></div>
<div class="layer layer--trees" data-speed="1"></div>
<div class="layer layer--front" data-speed="1.4"></div>

عدد 1 یعنی سرعت عادی. کمتر از یک یعنی کندتر (دورتر) و بیشتر از یک یعنی سریع‌تر (نزدیک‌تر).

قاعدهٔ طلایی پارالاکس: کم بگذار

بزرگ‌ترین اشتباه، شدت زیاد است. اگر لایه‌ها خیلی سریع نسبت به هم حرکت کنند، به‌جای عمق، حس سرگیجه ایجاد می‌شود. قاعدهٔ عملی من:

نوع لایه سرعت پیشنهادی نتیجه
پس‌زمینهٔ دور ۰٫۷ تا ۰٫۸۵ عمق ملایم و باورپذیر
لایهٔ میانی ۰٫۹ تا ۱ تقریباً طبیعی
عناصر تزئینی جلو ۱٫۱ تا ۱٫۲۵ کمی برجستگی
هر چیز خارج از این بازه — معمولاً حس مصنوعی

هرگز متن اصلی را پارالاکس نکن. متنی که با سرعت متفاوت حرکت می‌کند، خواندنش سخت است و کاربر ناخودآگاه اذیت می‌شود.

لایه‌بندی: ساختن عمق بدون حرکت

نکته‌ای که کمتر گفته می‌شود: بخش بزرگی از حس عمق، اصلاً به حرکت ربطی ندارد. با سه ابزار ساده می‌توانی بدون یک خط جاوااسکریپت عمق بسازی:

۱. تاری تدریجی

.layer--far  { filter: blur(3px); opacity:.6; }
.layer--mid  { filter: blur(1px); opacity:.85; }
.layer--near { filter: none;      opacity:1; }

هرچه دورتر، تارتر و کم‌رنگ‌تر. دقیقاً همان کاری که لنز دوربین انجام می‌دهد.

۲. مقیاس و اندازهٔ نسبی

عناصر دورتر را کوچک‌تر و با کنتراست کمتر بگذار. این ساده‌ترین راه ساخت سلسله‌مراتب بصری است.

۳. گرادیان‌های پوششی

.scene::after{
  content:'';
  position:absolute; inset:0;
  background:linear-gradient(180deg,
    rgba(0,0,0,.7) 0%,
    transparent 35%,
    transparent 65%,
    rgba(0,0,0,.85) 100%);
  pointer-events:none;
}

این گرادیان بالا و پایین پرده را تیره می‌کند و همان حس «کادر سینمایی» را می‌سازد. صفت pointer-events:none را فراموش نکن؛ وگرنه این لایه جلوی کلیک روی دکمه‌ها را می‌گیرد.

تایپوگرافی متحرک و انیمیشن متن فارسی در وب

تایپوگرافی متحرک: شخصیت صفحه

متن متحرک، امضای بصری صفحه‌های سینمایی است. اما مرز باریکی بین «چشمگیر» و «آزاردهنده» وجود دارد. سه الگوی امن را می‌بینیم.

الگوی ۱: ظهور کلمه‌به‌کلمه

ابتدا متن را به کلمه‌ها می‌شکنیم:

function splitWords(el){
  const words = el.textContent.trim().split(/\s+/);
  el.innerHTML = words
    .map(w => `<span class="w"><span class="w__in">${w}</span></span>`)
    .join(' ');
  return el.querySelectorAll('.w__in');
}
.w{display:inline-block; overflow:hidden; vertical-align:top;}
.w__in{display:inline-block;}

و انیمیشنش:

document.querySelectorAll('[data-split]').forEach(el => {
  const inner = splitWords(el);
  gsap.from(inner, {
    yPercent: 110,
    duration: .7,
    stagger: .04,
    ease: 'power3.out',
    scrollTrigger: { trigger: el, start: 'top 82%' }
  });
});

منطقش را دقت کن: هر کلمه در یک ظرف با overflow:hidden قرار می‌گیرد و از پایین بالا می‌آید. نتیجه، همان افکت «بالا آمدن از پشت خط» است که در تیتراژ فیلم‌ها می‌بینی.

نکتهٔ مهم فارسی: شکستن متن فارسی به حرف، اتصال حروف را خراب می‌کند و کلمه به‌هم می‌ریزد. برای فارسی همیشه به کلمه بشکن، نه حرف. این نکته را در هیچ آموزش انگلیسی‌ای پیدا نمی‌کنی.

الگوی ۲: روشن‌شدن تدریجی متن با اسکرول

افکتی که این روزها زیاد می‌بینی: متن خاکستری است و با اسکرول کلمه‌به‌کلمه روشن می‌شود.

const inner = splitWords(document.querySelector('.manifesto'));
gsap.fromTo(inner,
  { opacity: .18 },
  {
    opacity: 1,
    stagger: .5,
    ease: 'none',
    scrollTrigger: {
      trigger: '.manifesto',
      start: 'top 75%',
      end: 'bottom 55%',
      scrub: .5,
    }
  }
);

این الگو برای پردهٔ «مسئله» یا بیانیهٔ برند فوق‌العاده است، چون کاربر را مجبور می‌کند متن را واقعاً بخواند.

الگوی ۳: عنوان بزرگ با حرکت افقی

gsap.to('.marquee__inner', {
  xPercent: -50,
  ease: 'none',
  scrollTrigger: {
    trigger: '.marquee',
    start: 'top bottom',
    end: 'bottom top',
    scrub: 1,
  }
});

برای این افکت، محتوای نوار را دو بار تکرار کن تا حرکت بی‌انتها به‌نظر برسد.

قواعد امنیتی تایپوگرافی متحرک

  • فقط یکی دو عنوان در کل صفحه. اگر همهٔ متن‌ها متحرک باشند، هیچ‌کدام خاص نیستند.
  • متن‌های بلند را هرگز متحرک نکن. پاراگراف‌های توضیحی باید ساده و ثابت باشند.
  • فاصلهٔ پلکانی را کوتاه بگذار. مقدار stagger بالای ۰٫۰۸ باعث می‌شود کاربر منتظر بماند.
  • بعد از انیمیشن، متن کاملاً طبیعی باشد. هیچ transform باقی‌مانده‌ای نباید بماند.
  • خروجی نهایی را با ذره‌بین مرورگر تست کن. عنصرهای شکسته نباید متن را برای موتور جستجو یا صفحه‌خوان خراب کنند.

نکتهٔ دسترس‌پذیری که همه فراموش می‌کنند

وقتی متن را به spanهای جدا می‌شکنی، بعضی صفحه‌خوان‌ها آن را کلمه‌به‌کلمه و بریده‌بریده می‌خوانند. راه‌حل ساده:

<h2 data-split aria-label="متن کامل عنوان اینجا">
  متن کامل عنوان اینجا
</h2>

صفت aria-label باعث می‌شود صفحه‌خوان متن یکپارچه را بخواند و ساختار شکسته را نادیده بگیرد.

شکستن متن فارسی به کلمه برای انیمیشن بدون خرابی حروف

ترکیب همه‌چیز در یک پرده

حالا ببینیم یک پردهٔ کامل با هر سه تکنیک چطور می‌شود:

// ۱) لایه‌های پارالاکس
gsap.to('.hero__sky',  { yPercent: 12, ease:'none',
  scrollTrigger:{ trigger:'.scene--hero', start:'top top',
                  end:'bottom top', scrub:true }});
gsap.to('.hero__hills',{ yPercent: 6,  ease:'none',
  scrollTrigger:{ trigger:'.scene--hero', start:'top top',
                  end:'bottom top', scrub:true }});

// ۲) پرده تیره می‌شود
gsap.to('.hero__veil', { opacity: .95, ease:'none',
  scrollTrigger:{ trigger:'.scene--hero', start:'top top',
                  end:'bottom top', scrub:true }});

// ۳) عنوان کلمه‌به‌کلمه بالا می‌آید
const words = splitWords(document.querySelector('.hero__title'));
gsap.from(words, { yPercent:110, duration:.8, stagger:.05,
                   ease:'power3.out', delay:.2 });

سه تکنیک، حدود پانزده خط کد، و نتیجه‌ای که شبیه کار یک استودیوی حرفه‌ای است. رمزش این است که هر سه تکنیک ملایم‌اند و با هم جمع می‌شوند، نه اینکه هرکدام جداگانه فریاد بزنند.

پرامپت ساخت این لایه

نقش: توسعه‌دهندهٔ فرانت‌اند متخصص انیمیشن و تایپوگرافی وب.

کار: لایهٔ عمق و تایپوگرافی متحرک را به صفحهٔ موجود اضافه کن.
ساختار HTML موجود را تغییر نده مگر برای شکستن متن به کلمه.

نیازها:
- پارالاکس با صفت data-speed؛ سرعت‌های بین ۰٫۷ تا ۱٫۲۵.
- گرادیان پوششی سینمایی بالا و پایین هر پردهٔ تصویری.
- تابع شکستن متن به «کلمه» (نه حرف) — متن فارسی است و
  شکستن حرفی اتصال حروف را خراب می‌کند.
- عنوان هیرو: ظهور کلمه‌به‌کلمه از پایین با overflow پنهان.
- پردهٔ مسئله: روشن‌شدن تدریجی کلمات با scrub.

قیدها:
- روی هر عنصر شکسته‌شده aria-label با متن کامل بگذار.
- متن پاراگراف‌های بلند اصلاً متحرک نشود.
- در prefers-reduced-motion همهٔ این‌ها غیرفعال و متن طبیعی شود.
- بعد از پایان انیمیشن هیچ transform باقی‌مانده‌ای نماند.

خروجی: یک بلوک script + CSS لازم، با توضیح کوتاه دربارهٔ
اینکه چرا برای فارسی به کلمه می‌شکنیم نه حرف.

آن قید مربوط به فارسی را حتماً بنویس؛ مدل‌ها به‌طور پیش‌فرض کد انگلیسی‌محور تولید می‌کنند و متن فارسی را حرف‌به‌حرف می‌شکنند. تجربهٔ عملی این نوع مرزگذاری را در پرامپت‌نویسی به زبان ساده بیشتر توضیح داده‌ایم.

پرسش‌های پرتکرار

پارالاکس روی موبایل هم باید فعال باشد؟
معمولاً با شدت خیلی کمتر یا اصلاً نه. صفحهٔ کوچک، فضای کافی برای دیده‌شدن اختلاف لایه‌ها ندارد و فقط پردازش اضافه می‌شود.

چرا متن فارسی بعد از شکستن به‌هم می‌ریزد؟
چون حروف فارسی به هم می‌چسبند و شکل هر حرف به همسایه‌اش بستگی دارد. وقتی هر حرف را در یک span جدا می‌گذاری، این اتصال از بین می‌رود. راه‌حل: فقط به کلمه بشکن.

افکت روشن‌شدن تدریجی متن، سئو را خراب نمی‌کند؟
نه، چون متن در HTML موجود است و فقط شفافیتش تغییر می‌کند. مشکل زمانی پیش می‌آید که متن با جاوااسکریپت ساخته شود.

چند تکنیک در یک صفحه زیاد است؟
قاعدهٔ من: حداکثر سه تکنیک حرکتی متمایز در کل صفحه، که هرکدام با نظم تکرار شوند. بیشتر از آن، صفحه شلوغ و بی‌هویت می‌شود.

جمع‌بندی

عمق را با پارالاکس ملایم (۰٫۷ تا ۱٫۲۵)، تاری تدریجی و گرادیان‌های پوششی بساز. شخصیت را با تایپوگرافی متحرک بده، اما فقط روی یکی دو عنوان و همیشه با شکستن به کلمه در متن فارسی. و هر جا شک کردی، شدت را کم کن — در این سبک، کم‌گذاشتن تقریباً همیشه بهتر از زیاد‌گذاشتن است.

با این درس، بخش ابزارها تمام شد. در درس بعدی وارد مرحلهٔ هیجان‌انگیز می‌شویم: روش پرامپت‌نویسی برای ساخت سایت اسکرولی — اینکه چطور همهٔ این دانش را به مدل منتقل کنی تا کد قابل‌استفاده تحویل بگیری. مسیر کامل را در نقشهٔ راه ببین و در @MrChatGPT_IR همراه ما باش.

— (0 رأی)

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *