ویژگی تصویر

افکت سایه در حرکت با CSS

  /  CSS   /  افکت سایه در حرکت با CSS
بنر تبلیغاتی الف

سایه‌های متحرک (motion shadow) یکی از روش‌های قدرتمند برای ایجاد عمق، واقع‌گرایی و تاکید در رابط کاربری هستند. با ترکیب خواص CSS مانند box-shadow، filter، transform و انیمیشن‌ها می‌توان افکت‌هایی از سایه‌های نرم و ملایم تا سایه‌های واقع‌نما و دینامیک ساخت که به تعاملات کاربر پاسخ می‌دهند.

مبانی: box-shadow و transition

ساده‌ترین راه برای اضافه کردن سایه استفاده از box-shadow است. با افزودن transition می‌توان تغییرات سایه هنگام هاور یا تغییر کلاس را نرم کرد.

.card {
  width: 220px;
  height: 140px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.12);
  transition: box-shadow 300ms ease, transform 300ms ease;
}

.card:hover {
  transform: translateY(-8px);
  box-shadow: 0 20px 40px rgba(0,0,0,0.18);
}

این قطعه کد یک کارت ساده را نشان می‌دهد که با هاور بالا می‌آید و سایه‌اش بزرگ‌تر و نرم‌تر می‌شود. اما تغییر مستقیم box-shadow می‌تواند هزینه پردازشی بالایی داشته باشد، مخصوصاً برای المان‌های فراوان یا انیمیشن‌های پیوسته.

سایه متحرک با keyframes

انیمیشن‌های keyframe برای افکت‌هایی که دائماً تکرار می‌شوند یا ریتم مشخصی دارند مناسب‌اند. در مثال زیر سایه‌ای که در طول زمان کشیده می‌شود را می‌بینیم:

@keyframes float-shadow {
  0% {
    box-shadow: 0 8px 20px rgba(0,0,0,0.12);
    transform: translateY(0);
  }
  50% {
    box-shadow: 0 24px 48px rgba(0,0,0,0.16);
    transform: translateY(-12px);
  }
  100% {
    box-shadow: 0 8px 20px rgba(0,0,0,0.12);
    transform: translateY(0);
  }
}

.floating {
  animation: float-shadow 3s ease-in-out infinite;
}

در این مثال box-shadow و transform همزمان تغییر می‌کنند تا حس شناوری (floating) ایجاد شود. اما توجه کنید که تغییر مکرر box-shadow می‌تواند باعث بار روی رندر شود؛ پس این روش برای المان‌های کم و هدفمند مناسب‌تر است.

روش بهینه: استفاده از pseudo-element و transform

برای بهبود عملکرد، پیشنهاد می‌شود سایه را در یک pseudo-element ایجاد کنید و تنها transform و opacity آن را انیمیت کنید. این روش از GPU استفاده می‌کند و از Repaint/Relayout جلوگیری می‌نماید.

.avatar {
  position: relative;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: url(avatar.jpg) center/cover;
  overflow: visible;
}

.avatar::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 100%;
  width: 80%;
  height: 24px;
  background: rgba(0,0,0,0.18);
  border-radius: 50%;
  transform: translateX(-50%) scaleX(1);
  filter: blur(8px);
  transition: transform 300ms ease, opacity 300ms ease;
  opacity: 1;
}

.avatar:hover::after {
  transform: translateX(-50%) scaleX(1.6) translateY(6px);
  opacity: 0.9;
}

در این نمونه، سایه به صورت یک pseudo-element نصفه‌بیضی ایجاد شده و تنها transform/opacity آن تغییر می‌کند که بسیار سبک‌تر از انیمیشن مستقیم box-shadow است. filter: blur باعث نرمی سایه می‌شود اما استفاده بیش از حد فیلترها هم هزینه دارد.

drop-shadow در filter برای سایه‌های تصویری

اگر بخواهید سایه‌ای برای یک تصویر با شفافیت داشته باشید، filter: drop-shadow گزینه مناسبی است. این فیلتر بر روی تصاویر و svg بهتر عمل می‌کند چون شکل واقعی تصویر را دنبال می‌کند.

.icon {
  filter: drop-shadow(0 8px 12px rgba(0,0,0,0.25));
  transition: filter 220ms ease, transform 220ms ease;
}

.icon:hover {
  transform: translateY(-6px);
  filter: drop-shadow(0 18px 28px rgba(0,0,0,0.28));
}

drop-shadow برای اجسام با شفافیت لبه (مثل آیکون‌ها) طبیعی‌تر است، اما همانند box-shadow، تغییر مکرر فیلترها می‌تواند پردازش‌بر باشد.

ویژگی‌ها و معنای سریع

خاصیتشرح
box-shadowافزودن سایه به باکس — شامل افست، بلور و رنگ
filter: drop-shadow()سایه‌ای بر اساس شکل محتوای المان (برای تصاویر/SVG مناسب)
transformحرکت، مقیاس و چرخش المان یا pseudo-element (انیمیشن سبک‌تر)
will-changeپیش‌اطلاع به مرورگر درباره انیمیت شدن یک خاصیت برای بهینه‌سازی

پایداری و دسترس‌پذیری

برای کاربران با نیازهای خاص، انیمیشن‌های دائمی یا شدید می‌توانند آزاردهنده باشند. همواره media query زیر را لحاظ کنید:

@media (prefers-reduced-motion: reduce) {
  .floating, .avatar, .icon {
    animation: none !important;
    transition: none !important;
  }
}

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

تعامل داینامیک با حرکت ماوس (مثال پیشرفته)

برای افکتی که سایه را بر اساس موقعیت اشاره‌گر تغییر می‌دهد، بهتر است از CSS variables به همراه JavaScript استفاده کنید تا رندر سبکی داشته باشید:

.card {
  --dx: 0px;
  --dy: 10px;
  --blur: 20px;
  box-shadow: var(--dx) var(--dy) var(--blur) rgba(0,0,0,0.18);
  transition: box-shadow 120ms linear;
}

/* JS */const card = document.querySelector('.card');
card.addEventListener('mousemove', e => {
  const rect = card.getBoundingClientRect();
  const dx = ((e.clientX - rect.left) / rect.width - 0.5) * 30;
  const dy = ((e.clientY - rect.top) / rect.height - 0.5) * 30 + 10;
  card.style.setProperty('--dx', dx + 'px');
  card.style.setProperty('--dy', dy + 'px');
});

در این نمونه JavaScript فقط متغیرهای CSS را آپدیت می‌کند. اگرچه box-shadow هنوز تغییر می‌کند و هزینه‌ای دارد، اما با محدود کردن نرخ آپدیت (throttle) یا با انیمیت جایگزین کردن یک pseudo-element و تغییر transform، می‌توان عملکرد را بهتر کرد.

نکات حرفه‌ای و بهینه‌سازی

  • اجتناب از انیمیت مستقیم box-shadow در تعداد زیاد؛ از pseudo-element و transform استفاده کنید.
  • استفاده از will-change: transform یا opacity زمانی که می‌دانید المان قرار است انیمیت شود.
  • برای آیکون‌ها و تصاویر از filter: drop-shadow استفاده کنید تا سایه شکل محتوا را دنبال کند.
  • در انیمیشن‌های پیوسته، نرخ فریم و مصرف CPU را با throttle یا requestAnimationFrame مدیریت کنید.
  • همیشه prefers-reduced-motion را رعایت کنید تا دسترس‌پذیری حفظ شود.

جمع‌بندی

ایجاد افکت سایه در حرکت با CSS ترکیبی از هنر و مهندسی است: انتخاب بین واقع‌گرایی و عملکرد. با به‌کارگیری pseudo-elementها، transform و CSS variables می‌توانید افکت‌های زیبا و در عین حال بهینه بسازید. برای رفتارهای پیچیده‌تر، از JavaScript برای کنترل متغیرها استفاده کنید و همواره مسائل دسترس‌پذیری و عملکرد را در نظر داشته باشید.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: