افکت کارت سه بعدی با CSS
افکت کارت سهبعدی (3D card effect) یکی از پرکاربردترین جلوههای بصری در طراحی رابط کاربری مدرن است. این افکت به کارتها عمق و احساس تعامل میدهد و معمولاً در کارتهای محصول، گالری، داشبورد و بخشهای معرفی استفاده میشود. در این مقاله اصول فنی، مثال عملی با کد، بهینهسازی عملکرد و ملاحظات دسترسپذیری را به زبان ساده شرح میدهیم.
اصول فنی: perspective و transform
برای ایجاد عمق در CSS از دو مفهوم مهم استفاده میکنیم: perspective و transform. perspective تعیین میکند که چگونه عناصر فرزند در فضای سهبعدی دیده شوند و transform وقتی با rotateX/rotateY/translateZ ترکیب شود، حالت سهبعدی ایجاد میکند. همچنین transform-style: preserve-3d برای حفظ مختصات سهبعدی در زیرعنصرها لازم است.
مثال پایه HTML و CSS
<div class="scene">
<div class="card">
<div class="card__face card__face--front">
<h3>Product</h3>
<p>Short description</p>
</div>
<div class="card__face card__face--back">
<p>Details & CTA</p>
</div>
</div>
</div>
/* CSS */.scene{
perspective: 1000px;
}
.card{
width: 300px;
height: 200px;
transform-style: preserve-3d;
transition: transform 0.6s cubic-bezier(.2,.8,.2,1);
}
.card__face{
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 10px;
overflow: hidden;
}
.card__face--back{
transform: rotateY(180deg);
}
.scene:hover .card{
transform: rotateY(15deg) rotateX(6deg);
}توضیح: این کد یک صحنه سهبعدی ساده میسازد. .scene وظیفهٔ perspective را دارد. .card با transform-style: preserve-3d به کارت اجازه میدهد که اجزای داخلش در فضای سهبعدی حفظ شوند. backface-visibility: hidden باعث میشود پشت کارت هنگام چرخش دیده نشود. در حالت hover یک چرخش سبک اعمال شده تا عمق محسوس شود.
افزودن نور و سایههای پویا با pseudo-elements
.card::before{
content: "";
position: absolute;
inset: 0;
background: linear-gradient(120deg, rgba(255,255,255,0.08), transparent 40%);
pointer-events: none;
transition: opacity 0.3s;
}
.scene:hover .card::before{
opacity: 1;
}توضیح: از یک شبهعنصر (::before) برای شبیهسازی نور استفاده میکنیم. شیب نرم و نیمهشفاف به کارت حس براقی و عمق میدهد بدون اضافهبار DOM. pointer-events: none تضمین میکند که شبهعنصر تداخل تعاملی نداشته باشد.
تعامل با ماوس: کاربرد JavaScript برای tilt پویا
const card = document.querySelector('.card');
const scene = document.querySelector('.scene');
scene.addEventListener('mousemove', (e) => {
const rect = scene.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
const rotateY = x * 20; // degrees
const rotateX = -y * 10;
card.style.transform = `rotateY(${rotateY}deg) rotateX(${rotateX}deg)`;
});
scene.addEventListener('mouseleave', () => {
card.style.transform = '';
});توضیح: این اسکریپت مبتنی بر موقعیت ماوس نسبت به عنصر صحنه، زاویهٔ چرخش کارت را محاسبه و اعمال میکند. وقتی ماوس خارج شود کارت به حالت اولیه بازمیگردد. برای روانی بیشتر میتوان از requestAnimationFrame استفاده کرد.
نسخه بهینه با requestAnimationFrame و حداقل تغییرات
let rafId;
scene.addEventListener('mousemove', (e) => {
if(rafId) cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(() => {
const rect = scene.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
const rotateY = x * 18;
const rotateX = -y * 10;
card.style.transform = `translateZ(10px) rotateY(${rotateY}deg) rotateX(${rotateX}deg)`;
});
});توضیح: استفاده از requestAnimationFrame به جای اعمال مستقیم در هر رویداد mousemove باعث میشود محاسبات و رندر در فریمهای مناسب انجام شود و عملکرد روانتر و مصرف CPU کمتر شود. همچنین translateZ کمی کارت را به سمت قلمرو دوربین نزدیکتر میکند تا عمق افزایش یابد.
ملاحظات دسترسپذیری و واکنشگرایی
- پشتیبانی از prefers-reduced-motion: برای کاربران حساس به انیمیشن باید انیمیشنها را غیرفعال یا کاهش داد.
- تعامل لمسی: روی موبایل hover کار نمیکند؛ بهتر است از ژستهای لمسی (touchstart) یا حالت تعاملی جایگزین استفاده کنید.
- خوانایی محتوا: مطمئن شوید متن روی کارت همچنان قابل خواندن است و کنتراست مناسب دارد.
نمونه CSS برای prefers-reduced-motion
@media (prefers-reduced-motion: reduce) {
.card, .card::before {
transition: none !important;
transform: none !important;
}
}توضیح: این قانون ساده تغییرات حرکتی را برای کاربرانی که ترجیح میدهند حرکت محدود باشد، غیرفعال میکند. استفاده از !important در این زمینه معقول است چون میخواهیم مطمئن شویم انیمیشنها قطع میشوند.
نکات بهینهسازی و بهترین شیوهها
- از will-change فقط برای عناصر محدود و در لحظهٔ نیاز استفاده کنید تا حافظهٔ GPU بهینه بماند.
- ترجیحاً انیمیشنها را روی خواص transform و opacity انجام دهید تا از repaint جلوگیری شود.
- برای مجموعهای از کارتها، perspective را در والد بالاتر قرار دهید تا محاسبات کمتر شوند.
- در صفحههای دارای تعداد زیاد کارت، فعالسازی انیمیشن تنها وقتی کارت در viewport است کمککننده است (Intersection Observer).
جدول سریع خصوصیات مهم
| خصوصیت | توضیح |
|---|---|
| perspective | طول کانونی یا عمق دید سهبعدی |
| transform-style | حفظ یا فروپاشی مختصات سهبعدی برای فرزندان |
| backface-visibility | نمایش یا عدم نمایش پشت عناصر هنگام چرخش |
| will-change | هشدار به مرورگر درباره خواصی که تغییر خواهند کرد |
جمعبندی و موارد کاربرد
افکت کارت سهبعدی با CSS ترکیبی از خواص ساده اما قدرتمند است که به محصول یا رابط کاربری شما جلوهٔ حرفهای میدهد. با رعایت نکات دسترسپذیری، بهینهسازی عملکرد و استفاده از JS بهصورت کنترلشده (requestAnimationFrame)، میتوان تجربهای چشمنواز و روان ایجاد کرد. این افکت بهخصوص برای صفحات محصول، پروفایلها، کارتهای اطلاعاتی و نمایش نمونهکارها مناسب است.
اگر میخواهید نمونهٔ کاملتر، شامل تصویر، دکمه و انیمیشن ورود هنگام اسکرول را ببینید، میتوانم کد نمونهٔ کاملتر و صفحهٔ واکنشگرا برای شما آماده کنم.
آیا این مطلب برای شما مفید بود ؟




