مقدمه

واژه‌ی transformation به معنای تبدیل یا تغییر شکل است. در CSS یک پراپرتی با نام transform وجود دارد که به ما امکان می‌دهد شکل یک عنصر را به فرم‌های مختلف تغییر دهیم. برای مثال، می‌توانیم یک عنصر را در دو یا سه بعد دوران دهیم (rotate)، اندازه‌اش را تغییر دهیم (scale)، آن را جابجا کنیم (translate) و یا آن را کج و معوج کنیم (skew). با استفاده از قابلیت‌های پراپرتی transform و مقادیر قابل تخصیص به آن، می‌توانیم انواع مختلفی از افکت‌های مربوط به transformation را روی عناصر وب اعمال کنیم و به‌خصوص وقتی این پراپرتی با پراپرتی‌های animation و transition ترکیب شود، امکانات فوق‌العاده‌ای را در اختیار ما قرار می‌دهد.مقدار پراپرتی transform می‌تواند یک یا چند تابع باشد که هر یک نوع خاصی از تبدیلات را انجام می‌دهند. اگر بخواهیم بیش از یک تابع را به عنوان مقدار این پراپرتی تعیین کنیم، باید آنها را با استفاده از فاصله (space) از هم جدا کنیم. در این درس، با انواع تبدیلاتی که می‌توان با استفاده از پراپرتی transform روی عناصر انجام داد و روش انجام این تبدیلات، آشنا خواهیم شد.

چرخاندن عناصر

برای ایجاد دوران یا چرخاندن (rotation) یک عنصر از تابع rotate به عنوان مقدار پراپرتی transform استفاده می‌شود. آرگومان این تابع یک مقدار زاویه‌ای است که می‌تواند صحیح یا اعشاری باشد و بر حسب یکی از واحدهای زیر سنجیده می‌شود:

  • deg: از عبارت degrees به معنای درجه گرفته شده. یک دایره 360deg است.
  • grad: از عبارت gradians گرفته شده. یک دایره 400grad است.
  • rad: از عبارت radians گرفته شده. یک دایره 2π rad یا تقریباً 6.28rad است.
  • turn: به معنای دور است و هر دایره 1turn در نظر گرفته می‌شود.

یک مقدار مثبت به معنای چرخش در جهت حرکت عقربه‌های ساعت و یک مقدار منفی به معنای چرخش در جهت خلاف حرکت عقربه‌هاست.

چرخش می‌تواند حول هر یک از محورهای X یا افقی، Y یا عمودی و Z یا محور قائم بر صفحه انجام شود. همانطور که در تصویر زیر می‌بینید، محور X از چپ‌به‌راست، محور Y از بالا به پایین (بر خلاف ریاضیات) و محور Z از صفحه به سمت ماست.

محورهای XYZ

مبدأ چرخش هم در حالت پیش‌فرض، مرکز شکل است اما می‌تواند هر نقطه‌ی دیگری هم باشد. تصویر زیر نشان دهنده‌ی حالت پیش‌فرض است که چرخش حول نقطه‌ی مرکزیِ شکل انجام می‌شود.

چرخاندن عناصر بر اساس نقطه مرکزی

اما با استفاده از پراپرتی transform-origin می توانیم مبدأ چرخش را تغییر دهیم. در تصویر زیر، نقطه‌ی گوشه‌‌ی بالا سمت چپ به عنوان مبدأ چرخش تعیین شده است.

چرخاندن عناصر بر اساس نقاط گوشه‌ای

پراپرتی transform-origin می تواند یک، دو یا سه مقدار را دریافت کند که به‌ترتیب، معرف فاصله‌ی افقی، عمودی و ارتفاعی از نقطه‌ی مرکزی است. این فاصله‌ها را می‌توان با استفاده از واحدهایی مانند پیکسل و درصد و یا با استفاده از کلمات کلیدی left، center، right، top و bottom تعیین کرد.

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

توابع rotate و rotateZ

توابع rotate و rotateZ هر دو کار یکسانی را انجام می‌دهند و آن چرخاندن عنصر حول محور Z است. مثال زیر را ببینید.

 Copy Icon CSS
.rotate{
  width: 10rem;
  height: 5rem;
  background: skyblue;
  margin: 5rem;
  transform: rotate(45deg);
}

استفاده از تابع rotate(45deg) به عنوان مقدار پراپرتی transform باعث شده که عنصر div انتخاب‌شده به اندازه‌ی 45 درجه حول محور Z بچرخد. مبدأ چرخش مرکز عنصر است و چرخش در جهت حرکت عقربه‌های ساعت انجام شده است (چون آرگومان تابع مثبت است).

تابع rotateX

تابع rotateX همانطور که از نامش پیداست، برای چرخاندن یک عنصر حول محور X به کار می‌رود. عملکرد این تابع در ترکیب با تابع perspective بهتر نشان داده می‌شود. مثال زیر را ببینید.

 Copy Icon CSS
.rotate{
  width: 10rem;
  height: 5rem;
  background: skyblue;
  margin: 5rem;
  transform: perspective(200px) rotateX(45deg);
}

نقش تابع perspective از نامش پیداست. این تابع با فعال کردن فضای سه‌بعدی برای یک عنصر، به صفحه عمق می‌دهد. علت اینکه تابع perspective را به صورت جداگانه بررسی نکردیم، این است که این تابع به‌تنهایی هیچ تأثیری روی شکل عنصر ندارد اما در ترکیب با سایر تبدیلات، تآثیر چشمگیری روی نتیجه دارد.

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

تابع rotateY

تابع rotateY برای چرخاندن عنصر حول محور Y کاربرد دارد. تأثیر استفاده از این تابع همراه با تابع perspective را در مثال زیر می‌بینید.

 Copy Icon CSS
.rotate{
width: 10rem;
height: 5rem;
background: skyblue;
margin: 5rem;
transform: perspective(200px) rotateY(45deg);
}

تابع rotate3d

تابع rotate3d یک عنصر را حول یک محور دلخواه در فضای سه‌بعدی می‌چرخاند. این کار از طریق تعریف یک بردار جهت (direction vector) در دستگاه مختصات سه‌بعدی انجام می‌شود. برای تعریف این بردار، به مؤلفه‌ی بردار در هر یک از سه جهت مقداری بین صفر و 1 داده می‌شود. به این ترتیب، عنصر مورد نظر حول بردار تعریف‌شده با زاویه‌ی داده‌شده می‌چرخد. مثال زیر، موضوع را کاملاً روشن می کند.

 Copy Icon CSS
.rotate{
width: 10rem;
height: 5rem;
background: skyblue;
margin: 5rem;
transform: perspective(200px) rotate3d(1, 1, 0, 45deg);
}

همانطور که می‌بینید، چهار آرگومان به تابع rotate3d پاس شده که سه تای اول مؤلفه‌های بردار در راستای محورهای X، Y و Z هستند. به این ترتیب، بردار جهت به صورت (1,1,0) تعیین شده است. آرگومان چهارم یعنی 45deg زاویه‌ی چرخش حول بردار جهت را تعیین می‌کند.

انتقال عناصر

نوع دیگری از تبدیلات(transformations) که می‌توان روی عناصر وب انجام داد، تبدیلات از نوع انتقال (translation) هستند. یک تبدیل از نوع translation باعث جابجایی یا انتقال عنصر در صفحه می‌شود. در ادامه، با توابعی که این نوع تبدیلات را انجام می‌دهند، آشنا می‌شویم.

تابع translate

تابع translate یک عنصر را در فضای دو بعدی جابجا می‌کند. این تابع می‌تواند یک یا دو آرگومان را دریافت کند که به ترتیب، معرف محور X و Y هستند. جریان و چینش کلی صفحه با جابجا کردن یک عنصر تغییری نمی‌کند و بعد از جابجایی عنصر، در محل سابق آن عنصر فضای خالی نمایش داده می‌شود.

 Copy Icon CSS
div{
  width: 5rem;
  height: 5rem;
  display: inline-block;
}

.one{
  background: orangered;
}

.two{
  background: rebeccapurple;
  transform: translate(2rem, 2rem);
}

.three{
  background: skyblue;
}

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

توابع translateX و translateY به ترتیب، برای انتقال به صورت افقی و عمودی دریک بعد کاربرد دارند و به جای آنها هم می‌توان از تابع translate استفاده کرد. در واقع، translateX(1rem) معادل translate(1rem, 0) است و translateY(1rem) معادل translate(0, 1rem) است.

تابع translateZ

تابع translateZ عنصر را در راستای محور Z جابجا می‌کند. تأثیر استفاده از این تابع تنها زمانی مشخص خواهد بود که به همراه تابع perspective مورد استفاده قرار گیرد.

 Copy Icon CSS
.two{
  background: rebeccapurple;
  transform: perspective(200px) translateZ(2rem);
}

با اجرای کد بالا خواهید دید که باکس بنفش‌رنگ که با استفاده از تابع translateZ جابجا شده، در ترکیب با تابع perspective باعث شده که این عنصر به ما نزدیک‌تر به نظر برسد.

تابع translate3d

تابع translate3d به ما امکان می‌دهد که یک عنصر را در فضای سه‌بعدی جابجا کنیم. آرگومان اول این تابع بیانگر جابجایی در راستای محور X است، آرگومان دوم میزان جابجایی در راستای محور Y را مشخص می‌کند و آرگومان سوم به میزان جابجایی در راستای محور Z مربوط است.

 Copy Icon CSS
.two{
  background: rebeccapurple;
  transform: perspective(200px) translate3d(1rem, 2rem, 3rem);
}

با اجرای این مثال خواهید دید که عنصر مورد نظر به اندازه‌ی 1rem‌ به راست، 2rem به سمت پایین و 3rem به سمت ما جابجا شده است.

تغییر اندازه عناصر

تغییر اندازه یا تغییر مقیاس (scaling) عناصر، یکی دیگر از انواع تبدیلاتی است که می‌توانیم با استفاده از CSS روی عناصر وب انجام دهیم. توابعی که تبدیلات از نوع scaling را انجام می‌دهند، هم اندازه‌ی خود عنصر را تغییر می‌دهند و هم محتوای آن عنصر را.

بر خلاف توابع translation که یک مقدار اندازه‌ای را بر حسب واحدهایی مثل px و rem دریافت می‌کنند، توابع scaling مضربی از سایز اورجینال عنصر را به عنوان پارامتر دریافت می‌کنند. برای مثال، scale(1, 1) با هیچ تغییر اندازه‌ای همراه نیست اما scale(2, 3) باعث می‌شود که عنصر مورد نظر در راستای افقی دو برابر و در راستای عمودی سه برابر شود. البته لزومی ندارد که این مقادیر، صحیح باشند و امکان استفاده از مقادیر اعشاری مثل scale(1.25, 2.58) هم برای آرگومان این توابع وجود دارد.

در حالت پیش‌فرض، توابع scaling کار تبدیل عنصر را از مرکز عنصر انجام می‌دهند اما این رفتار را می‌توان با استفاده از پراپرتی transform-origin تغییر داد. در ضمن، توجه داشته باشید که تغییر اندازه‌ی یک عنصر تأثیری روی والد عنصر ندارد و چینش صفحه را تغییر نمی‌دهد. در تصویر زیر عنصر سمت چپ با سایز اورجینال خود نمایش داده شده، عنصر میانی از مرکز شکل به عنوان مبدأ برای تغییر سایز استفاده کرده و در عنصر سمت راست مبدأ در بالای عنصر قرار دارد. در ضمن، همانطور که می‌بینید، سایز عنصر والد تغییری نمی‌کند.

مبدأ تغییر مقیاس در CSS

تابع scale

تابع scale می‌تواند تغییر ابعاد عنصر را تنها در راستای محور X و یا در راستای هر دو محور X و Y در فضای دوبعدی انجام دهد. این تابع می‌تواند یک یا دو آرگومان دریافت کند. اگر یک آرگومان به این تابع داده شود، تغییر ابعاد را در راستای محور X انجام می‌دهد و اگر دو آرگومان تعیین شود، اولی برای تغییر در راستای X و دومی برای تغییر در راستای Y در نظر گرفته می‌شود.

 Copy Icon CSS
.scale{
  background: skyblue;
  text-align: center;
  transform: scale(2, 5);
  margin: 5rem auto;
  width: 10rem;
}

برای تغییر ابعاد در راستای محور X از تابع scaleX و برای تغییر در راستای محور Y از تابع scaleY استفاده می‌شود.

توابع scaleZ و scale3d

تابع scaleZ عنصر را در راستای محور Z تغییر مقیاس می‌دهد. البته این تابع اگر به تنهایی به کار رود، هیچ تأثیری نخواهد داشت و برای اینکه تأثیر آن به خوبی دیده شود، باید به همراه تابع perspective و تبدیل دیگری مثل rotateX به کار رود.

با استفاده از تابع scale3d‌ هم می‌توانیم عنصر را در سه بعد تغییر مقیاس دهیم. سه آرگومانی که این تابع دریافت می‌کند، به ترتیب، بیانگر میزان تغییر مقیاس در راستای محور X، Y و Z است.

کج و معوج کردن عناصر

آخرین نوع از تبدیلات که در این بخش آنها را بررسی می‌کنیم، تبدیلات از نوع skewing هستند که در با ایجاد اعوجاج و انحراف در شکل عنصر تغییر ایجاد می‌کنند. توابع مربوط به تبدیلات skewing، با دریافت یک زاویه در راستای محورهای X و Y باعث تغییر شکل در عنصر می‌شوند. همانند توابع مربوط به rotation، زاویه می‌تواند بر حسب هر یک از واحدهای درجه، رادیان، گرادیان و دور یا turn داده شود.

 Copy Icon CSS
.skew{
  background: skyblue;
  transform: skew(45deg, 20deg);
  width: 10rem;
  font-size: 2rem;
  text-align: center;
  margin: 5rem;
}

علاوه بر این، با استفاده از توابع skewX و skewY می‌توانیم تغییر شکل عنصر را در یک جهت انجام دهیم.

انجام چند تبدیل به صورت همزمان

همانطور که در مثال‌های این درس هم دیدیم، روی یک عنصر می‌توان بیش از یک تبدیل انجام داد. برای این کار، کافیست توابع مربوط به تبدیلات را به صورت یک لیست space separated یعنی لیستی که آیتم‌هایش با استفاده از کاراکتر فاصله از هم جدا شده‌اند، به عنوان مقدار پراپرتی transform تعیین کنیم. نکته‌ی مهمی که باید بدانید این است که وقتی یک عنصر چرخانده می‌شود، محورها هم به همراه عنصر جابجا می‌شوند. این مطلب را می‌توان با استفاده از یک مثال نشان داد. در کد زیر یک باکس ساده درون یک کانتینر وجود دارد که 45 درجه چرخانده شده است.

 Copy Icon CSS
.container{
  border: 1px solid black;
  width: 15rem;
  height: 15rem;
  margin: 5rem;
}

.box{
  transform: rotate(45deg);
  background: skyblue;
  width: 10rem;
  height: 10rem;
}

در نتیجه‌ی این چرخش، همانطور که در تصویر زیر می‌بینید، دستگاه مختصات هم به همراه عنصر چرخیده است.

چرحش محورهای مختصات به همراه عنصر

برای اثبات این موضوع، یک تابع translate(100px) به پراپرتی transform اضافه می‌کنیم:

Copy Icon CSS
transform: rotate(45deg) translateX(100px);

اگر این مثال را اجرا کنید، خواهید دید که باکس در راستای محور افقیِ جدید جابجا شده است.

وثتی بیش از یک تبدیل را برای یک عنصر تعیین می‌کنیم، ترتیب توابع تبدیل مهم است. برای مثال، اگر در کد بالا، ترتیب دو تبدیل موجود را عوض کنیم، نتیجه‌ی متفاوتی رادریافت خواهیم کرد، چون این بار ترتیب اجرای تبدیلات فرق دارد؛ باکس ما اول در راستای محور X جابجا می‌شود و سپس، چرخانده می‌شود.

مثال: ساخت شکل قلب

در این بخش، با استفاده از توابع مربوط به transform شکل یک قلب را ایجاد می‌کنیم. یک قلب در واقع، از ترکیب یک مربع چرخانده‌شده با دو دایره همانند تصویر زیر بدست می‌آید.

ساخت شکل قلب در CSS

بنابراین، کاری که باید انجام دهیم این است که یک مربع را 45 درجه بچرخانیم و سپس، دو دایره را در مکان مناسب قرار دهیم. مربع را با استفاده از یک عنصر div ایجاد می‌کنیم و از شبه‌عنصرهای ::before و ::after برای ترسیم دایره‌ها استفاده می‌کنیم. کار را با ایجاد و چرخاندن مربع شروع می‌کنیم.

 Copy Icon CSS
.heart{
  border: 5px solid red;
  transform: rotate(4deg);
  width: 10rem;
  height: 10rem;
  margin: 10rem auto;
}

حالا همانطور که قرار گذاشتیم، با استفاده از شبه‌عنصرهای ::before و ::after دو دایره ایجاد می‌کنیم. نکته اینکه برای ایجاد یک دایره کافیست پراپرتی border-radius را برای یک مربع روی 50% تنظیم کنیم.

 Copy Icon CSS
.heart::after, .heart::before{
  border-radius: 50%;
  content: '';
  width: 10rem;
  height: 10rem;
  position: absolute;
  background: red;
}

در حال حاضر، دو دایره در مرکز مربع روی هم قرار دارند و باید آنها را به سمت طرفین جابجا کنیم. یادآوری می‌کنم که دستگاه مختصات هم به همراه مربع چرخیده و این موضوع را باید در هنگام جابجایی دایره‌ها در نظر داشته باشیم. دایره‌ی سمت چپ را به میزان 5rem (یعنی نصف سایز مربع) در راستای محور X به سمت چپ جابجا می‌کنیم و دایره‌ی سمت راست را به همین میزان در راستای محور Y رو به بالا جابجا می‌کنیم. علاوه بر این، مربع را با رنگ قرمز پر می‌کنیم تا شکل قلب کامل شود.

 Copy Icon CSS
.heart{
  border: 5px solid red;
  transform: rotate(45deg);
  width: 10rem;
  height: 10rem;
  margin: 10rem auto;
  background: red;
}

.heart::after, .heart::before{
  border-radius: 50%;
  content: '';
  width: 10rem;
  height: 10rem;
  position: absolute;
  background: red;
}

.heart::before{
  transform: translateX(-5rem);
}

.heart::after{
  transform: translateY(-5rem);
}

مثال: ساخت یک مکعب

حالا اجازه دهید تا شکل یک مکعب سه‌بعدی را با استفاده از توابع transform ایجاد کنیم. برای این کار، به یک عنصر کانتینر برای مکعب، خودِ مکعب و یک عنصر برای هر یک از شش وجه مکعب نیاز داریم. این عناصر را به صورت زیر ایجاد و استایل‌دهی می‌کنیم.

 Copy Icon CSS
.container{
  width: 10rem;
  height: 10rem;
  perspective: 500px;
  margin: 5rem;
}

.cube{
  position: relative;
  width: 10rem;
  height: 10rem;
  transform-style: preserve-3d;
  transform: rotate3d(1, 1, 0, 45deg);
}

.face{
  width: 10rem;
  height: 10rem;
  background: skyblue;
  border: 2px solid black;
  position: absolute;
  opacity: 0.5;
  text-align: center;
}

در این کد یک پراپرتی جدید با نام transform-style دیده می‌شود. در حالت پیش‌فرض، فرزندان یک عنصر به صورت تخت‌شده روی یک صفحه یعنی به صورت دو بعدی نمایش داده می‌شوند. اما از آنجایی که ما می‌خواهیم یک مکعب سه‌بعدی ایجاد کنیم، پراپرتی transform-style را روی مقدار preserve-3d تنظیم می‌کنیم که باعث می‌شود عناصر فرزند مکعب در فضای سه‌بعدی باقی بمانند.

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

در حالت عادی دیدن اینکه چه اتفاقی رخ می‌دهد، سخت است و به همین خاطر، مکعب را چرخانده‌ایم تا آن را از زاویه‌ی 45 درجه ببینیم که به ما امکان می‌دهد که ساختار سه‌بعدی را بهتر ببینیم. به علاوه، برای اینکه مکعب بهتر دیده شود، میزان opacity را روی 0.5 تنظیم کرده‌ایم.

حالا باید هر یک از وجوه را در جهت مناسب بچرخانیم. وجه روبرو نیازی به چرخش ندارد، چون همین الان هم رو به جلو است. وجه پشتی را باید 180 درجه حول محور Y بچرخانیم، وجوه چپ و راست را باید 90 درجه حول محور Y بچرخانیم (به‌ترتیب -90 و 90 درجه) و وجوه بالایی و پایینی هم باید 90 درجه حول محور X چرخانده شوند. این کارها را در کدهای زیر انجام داده ایم.

 Copy Icon CSS
.container{
  width: 10rem;
  height: 10rem;
  perspective: 500px;
  margin: 5rem;
}

.cube{
  position: relative;
  width: 10rem;
  height: 10rem;
  transform-style: preserve-3d;
  transform: rotate3d(1, 1, 0, 45deg);
}

.face{
  width: 10rem;
  height: 10rem;
  background: skyblue;
  border: 2px solid black;
  position: absolute;
  opacity: 0.5;
  text-align: center;
}

.back{
  transform: rotateY(180deg);
}

.left{
  transform: rotateY(-90deg);
}

.right{
  transform: rotateY(90deg);
}

.top{
  transform: rotateX(90deg);
}

.bottom{
  transform: rotateX(-90deg);
}

الان همه‌ی وجوه مکعب به درستی چرخانده شده‌اند اما هنوز در مرکز مکعب قرار دارند. از آنجایی که سایز مکعب برابر با 10rem است و وجوه آن در مرکز قرار دارند، هر وجه باید به میزان 5rem در جهت صحیح جابجا شود. جهت صحیح برای وجوه جلو و عقب در راستای محور Z است و وجوه چپ و راست باید در راستای محور X و وجوه بالا و پایین باید در راستای محور Y جابجا شوند. به این ترتیب، داریم:

 Copy Icon CSS
.container{
  width: 10rem;
  height: 10rem;
  perspective: 500px;
  margin: 5rem;
}

.cube{
  position: relative;
  width: 10rem;
  height: 10rem;
  transform-style: preserve-3d;
  transform: rotate3d(1, 1, 0, 45deg);
}

.face{
  width: 10rem;
  height: 10rem;
  background: skyblue;
  border: 2px solid black;
  position: absolute;
  opacity: 0.5;
  text-align: center;
}

.front{
  transform: translateZ(5rem);
}

.back{
  transform: translateZ(-5rem) rotateY(180deg);;
}

.left{
  transform: translateX(-5rem) rotateY(-90deg);
}

.right{
  transform: translateX(5rem) rotateY(90deg);
}

.top{
  transform: translateY(-5rem) rotateX(90deg);
}

.bottom{
  transform: translateY(5rem) rotateX(-90deg);
}