چهار ویژگی جدید CSS برای ورود و خروج روان انیمیشن ها

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

برای پر کردن این شکاف‌ها، کروم 116 و 117 شامل چهار ویژگی جدید پلتفرم وب هستند که انیمیشن‌ها و انتقال‌ها را برای ویژگی‌های گسسته امکان‌پذیر می‌کنند.

این چهار ویژگی جدید عبارتند از:

  • امکان متحرک سازی display و content-visibility در یک جدول زمانی فریم کلیدی (از Chrome 116).
  • ویژگی transition-behavior با کلمه کلیدی allow-discrete برای فعال کردن انتقال خصوصیات گسسته مانند display (از Chrome 117).
  • قانون @starting-style برای متحرک سازی جلوه های ورودی از display: none و در لایه بالایی (از Chrome 117).
  • ویژگی overlay برای کنترل رفتار لایه بالایی در طول یک انیمیشن (از Chrome 117). ## انیمیشن ها را در فریم های کلیدی نمایش دهید

از Chrome 116، می‌توانید از display و content-visibility در قوانین فریم کلیدی استفاده کنید. اینها سپس در زمانی که فریم کلیدی رخ می دهد، با هم عوض می شوند. برای پشتیبانی از این به مقادیر جدید اضافی نیاز نیست:

.card {
  animation: fade-out 0.5s forwards;
}

@keyframes fade-out {
  100% {
    opacity: 0;
    display: none;
  }
}

مثال قبلی کدورت را روی 0 در مدت زمان 0.5 ثانیه متحرک می کند و سپس نمایش را روی هیچ تنظیم می کند. علاوه بر این، کلمه کلیدی forwards تضمین می کند که انیمیشن در حالت پایانی خود باقی می ماند، به طوری که عنصری که روی آن اعمال می شود display: none و opacity: 0 .

این یک مثال ساده است که کارهایی را که می‌توانید با یک انتقال انجام دهید تقلید می‌کند (دمو در بخش انتقال را ببینید). با این حال، انتقال‌ها قادر به ایجاد انیمیشن‌های پیچیده‌تر نیستند، مانند مثال زیر:

.card {
  animation: spin-and-delete 1s ease-in forwards;
}

@keyframes spin-and-delete {
  0% {
    transform: rotateY(0);
    filter: hue-rotate(0);
  }
  80% {
    transform: rotateY(360deg);
    filter: hue-rotate(180deg);
    opacity: 1;
  }
  100% {
    opacity: 0;
    display: none;
  }
}

انیمیشن spin-and-delete یک انیمیشن خروجی است. ابتدا کارت روی محور y می‌چرخد، از طریق یک چرخش رنگی اجرا می‌شود، و سپس با 80% در خط زمانی، کدورت خود را از 1 به 0 تغییر می‌دهد. در نهایت، کارت از display: block به display: none .

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

.spin-out {
   animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
 document.querySelector('.card').classList.add('spin-out');
})

مثال بالا اکنون دارای یک حالت پایانی display:none . موارد زیادی وجود دارد که می‌خواهید آن را بیشتر کنید و گره DOM را با یک بازه زمانی حذف کنید تا ابتدا انیمیشن به پایان برسد.

انتقال انیمیشن های گسسته

برخلاف زمانی که ویژگی‌های گسسته را با فریم‌های کلیدی متحرک می‌کنید، برای انتقال ویژگی‌های گسسته، باید از حالت رفتار انتقال allow-discrete استفاده کنید.

ویژگی transition-behavior

حالت allow-discrete چیزی است که انتقال گسسته را ممکن می‌کند و مقداری از ویژگی transition-behavior است. transition-behavior دو مقدار را می پذیرد: normal و allow-discrete .

.card {
  transition: opacity 0.25s, display 0.25s;
  transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}

.card.fade-out {
  opacity: 0;
  display: none;
}
توجه: این دمو انتقال تکنیک متفاوتی را نسبت به اولین نسخه نمایشی انیمیشن نشان می دهد، اما از نظر بصری شبیه به هم به نظر می رسد.

کوتاه‌نویسی transition نیز این مقدار را تعیین می‌کند، بنابراین می‌توانید این ویژگی را حذف کنید و به جای آن از کلمه کلیدی allow-discrete در انتهای خلاصه‌نویسی transition برای هر انتقال استفاده کنید.

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

اگر چندین ویژگی گسسته را متحرک می کنید، باید پس از هر ویژگی که می خواهید متحرک سازی کنید allow-discrete اضافه کنید. مثلا:

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

قانون @starting-style برای انیمیشن های ورودی

تاکنون، این مقاله به انیمیشن‌های خروجی پرداخته است، برای ایجاد انیمیشن‌های ورودی باید از قانون @starting-style استفاده کنید.

از @starting-style برای اعمال سبکی استفاده کنید که مرورگر بتواند قبل از باز شدن عنصر در صفحه جستجو کند. این حالت "قبل از باز" است (جایی که از آن در حال انیمیشن هستید).

/*  0. BEFORE-OPEN STATE   */
/*  Starting point for the transition */
@starting-style {
  .item {
    opacity: 0;
    height: 0;
  }
}

/*  1. IS-OPEN STATE   */
/*  The state at which the element is open + transition logic */
.item {
  height: 3rem;
  display: grid;
  overflow: hidden;
  transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}

/*  2. EXITING STATE   */
/*  While it is deleting, before DOM removal in JS, apply this
    transformation for height, opacity, and a transform which
    skews the element and moves it to the left before setting
    it to display: none */
.is-deleting {
  opacity: 0;
  height: 0;
  display: none;
  transform: skewX(50deg) translateX(-25vw);
}

اکنون برای این موارد لیست TODO هم حالت ورود و هم خروج دارید:

متحرک سازی عناصر به و از لایه بالایی

برای متحرک سازی عناصر به لایه بالا و از آن، @starting-style در حالت "باز" ​​مشخص کنید تا به مرورگر بگویید از کجا متحرک شود. برای یک گفتگو، حالت باز با ویژگی [open] تعریف می شود. برای پاپاور، از کلاس شبه :popover-open استفاده کنید.

یک مثال ساده از یک دیالوگ می تواند به شکل زیر باشد:

/*   0. BEFORE-OPEN STATE   */
@starting-style {
  dialog[open] {
    translate: 0 100vh;
  }
}

/*   1. IS-OPEN STATE   */
dialog[open] {
  translate: 0 0;
}

/*   2. EXIT STATE   */
dialog {
  transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
  translate: 0 100vh;
}

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

هنگام متحرک سازی یک پاپاور، به جای ویژگی open که قبلا استفاده شده بود، از کلاس شبه :popover-open استفاده کنید.

.settings-popover {
  &:popover-open {
    /*  0. BEFORE-OPEN STATE  */
    /*  Initial state for what we're animating *in* from, 
        in this case: goes from lower (y + 20px) to center  */
    @starting-style {
      transform: translateY(20px);
      opacity: 0;
    }
    
    /*  1. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;
  }
  
  /*  2. EXIT STATE  */
  /*  Initial state for what we're animating *out* to , 
      in this case: goes from center to (y - 50px) higher */
  transform: translateY(-50px);
  opacity: 0;
  
  /*  Enumerate transitioning properties, 
      including display and allow-discrete mode */
  transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}

خاصیت overlay

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

[open] {
  transition: opacity 1s, display 1s allow-discrete;
}

در عوض، overlay در انتقال یا انیمیشن به متحرک کردن overlay همراه با بقیه ویژگی‌ها اضافه کنید و مطمئن شوید که هنگام انیمیشن در لایه بالایی باقی می‌ماند. این بسیار نرمتر به نظر می رسد.

[open] {
  transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}

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

یادداشتی در مورد انتقال مشاهده

اگر در حال ایجاد تغییرات در DOM هستید، مانند افزودن و حذف عناصر از DOM، راه حل عالی دیگر برای انیمیشن های روان ، انتقال مشاهده است. در اینجا دو نمونه از نمونه های بالا با استفاده از انتقال view ساخته شده اند.

در این اولین نسخه نمایشی، به جای تنظیم @starting-style و دیگر تبدیل‌های CSS، انتقال‌های view این انتقال را مدیریت می‌کنند. انتقال view به این صورت تنظیم می شود:

ابتدا، در CSS، به هر کارت یک view-transition-name اختصاص دهید.

.card-1 {
  view-transition-name: card-1;
}

.card-2 {
  view-transition-name: card-2;
}

/* etc. */

سپس، در جاوا اسکریپت، جهش DOM (در این مورد، حذف کارت) را در یک انتقال view قرار دهید.

deleteBtn.addEventListener('click', () => {
  // Check for browser support
  if (document.startViewTransition) {
    document.startViewTransition(() => {
      // DOM mutation
      card.remove();
    });
  } 
  // Alternative if no browser support
  else {
    card.remove();
  }
})

اکنون، مرورگر می تواند محو شدن و تغییر شکل هر کارت را در موقعیت جدید خود کنترل کند.

نمونه دیگری از مواردی که می‌تواند مفید باشد، استفاده از نسخه نمایشی افزودن/حذف آیتم‌های فهرست است. در این مورد، باید به خاطر داشته باشید که برای هر کارت ایجاد شده یک view-transition-name منحصر به فرد اضافه کنید.

نتیجه

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