Написать пост

Четыре новые функции CSS для плавной анимации входа и выхода

Аватарка пользователя Елизавета Ржевская

Рассмотрели четыре новые функции CSS, которые обеспечивают плавную анимацию и переходы в Chrome 116 и 117.

Noveo Lead Web Developer Екатерина продолжает делиться с коллегами переводами полезных статей. В этот раз речь пойдет о создании плавных анимаций на веб-платформе: с новыми функциями Chrome 116 и 117 возможностей стало больше!

Движение является ключевой частью любого цифрового опыта, направляя пользователя от одного взаимодействия к следующему. Однако существуют определенные пробелы в плавных анимациях на веб-платформе. Сюда входит возможность легко создавать анимации для входа и выхода, а также плавно анимировать переход на верхний уровень для закрываемых элементов, таких как диалоговые окна и всплывающие панели.

Чтобы заполнить эти пробелы, в Chrome 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;
  }
}
		
Другиедискретные свойства меняют состояния, когда функция плавности перехода достигает отметки 50% времени работы. Однако свойства display и content-visibility переключаются в начале перехода (если вы анимируете вход) или в конце его (если вы анимируете выход).

В приведенном примере анимация плавно уменьшает непрозрачность до 0 за 0.5 секунды, после чего устанавливает свойство display в none. Кроме того, ключевое слово “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 принимает два значения: нормальное и разрешающе-дискретное.

			.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, обязательно используйте transition-behavior после сокращения, чтобы оно применялось в зависимости от специфики.

В этой демонстрации перехода используется не такая техника, как в первой анимационной демонстрации, но с визуальной точки зрения они выглядят похожими.

Сокращенная запись 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;
}
		
Совет: вы всегда можете включить дискретную анимацию с помощью * {transition-behavior: allow-discrete}, но убедитесь, что это находится в конце вашего CSS, чтобы предотвратить конфликты специфичности с сокращением transition.

Правило для анимации входа @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”, чтобы сообщить браузеру, откуда выполнять анимацию. Для диалогового окна состояние “открыто” определяется атрибутом [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 для более наглядной инкапсуляции стилей.

При анимации всплывающего окна используйте псевдокласс :popover-open вместо ранее использованного атрибута 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 помогает контролировать плавные переходы в верхний слой и из него. Вы можете увидеть разницу в этом простом примере. Если вы не применяете свойство overlay ко второму всплывающему окну при его скрытии, оно сначала переместится из верхнего слоя, скрывшись за другим всплывающим окном, прежде чем начнется анимация. Этот эффект не выглядит очень плавным.

Примечание о переходах между видами

Если вы вносите изменения в DOM, такие как добавление и удаление элементов, еще одним отличным способом создания плавных анимаций являются переходы между видами. Вот два из приведенных выше примеров, созданных с использованием межвидовых переходов.

В этой первой демонстрации вместо настройки @starting-style и других преобразований CSS переходы будут обрабатываться переходами представлений. Переход вида настраивается следующим образом:

Во-первых, в CSS присвойте каждой карточке индивидуальный view-transition-name:

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

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

/* etc. */
		

Затем в JavaScript оберните мутацию DOM (в данном случае удаление карты) в переход представления.

			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) для каждой создаваемой карточки.

Заключение

Эти новые функции платформы приближают нас к созданию плавных анимаций при входе и выходе на веб-платформе. Чтобы узнать больше, ознакомьтесь с этими ссылками:

  1. Introducing the popover API
  2. css-transitions-2 spec
  3. css-position-4 spec
  4. Оригинал статьи
Следите за новыми постами
Следите за новыми постами по любимым темам
2К открытий3К показов