Keyframe Animations

이재윤·2021년 11월 25일
1

HTML/CSS

목록 보기
3/4
post-thumbnail

이글은 An Interactive Guide to Keyframe Animations 를 번역한 글 입니다. 오역이 있을 수 있습니다.

이 글에서, CSS keyframe에 관해 깊게 살펴 볼 것 입니다. 동작하는 방식과, 멋있는 애니메이션 효과를 만드는 방법을 알아 보겠습니다.

💻 Syntax

CSS frame의 핵심은 서로다른 두 CSS를 연결하는 것 입니다.

아래는 -100%의 위치에서 0%로 요소를 수평으로 이동시키는 keyframe 입니다.

@keyframes slide-in {
 from {
  transform: translateX(-100%);
 }
 to {
  transform: translateX(0%);
 }
}

@keyframes 선언문에는 이름이 필요합니다. 위의 경우 slide-in 이라는 이름을 지정했습니다. 이름은 전역변수로 생각하면 됩니다.

Keyframe 애니메이션은 전역적으로 재사용되게끔 설계되었습니다. 이렇게 지정한 애니메이션을 animation 속성에 지정하면 됩니다.

transition 속성과 같이 animation 속성도 지속 시간을 설정해 줘야 합니다. 위 예시에서는 1초 (1000ms) 동안 애니메이션이 지속됩니다.

브라우저는 fromto 블록내의 선언을 지속시간동안 수행합니다. 이는 속성이 설정되자마자 일어납니다.

복수의 속성들을 하나의 애니메이션에 선언할 수도 있습니다. 아래는 여러개의 속성을 변경시키는 예시 입니다.

💻 Timing functions

CSS Transition 에서 timing function들에 대해 살펴 봤습니다.

transition 속성과 마찬가지로 같은 timing function들을 적용할 수 있습니다. 또한 transition과 같이 기본값은 ease 입니다.

animation-timing-function으로 지정할 수 있습니다.

💻 Looped animations

기본적으로, keyframe 애니메이션은 한번만 실행됩니다. 하지만 animation-iteration-count 속성으로 조절할 수 있습니다.

위 경우 처럼 정수를 직접 지정하기 보다는, infinite라는 값을 많이 사용합니다.

이 값은 로딩 스피너와 같은 곳에 지정할 수 있습니다.

❗ 스피너는 균일한 동작을 보여주어야 하기 때문에 linear timing function을 사용합니다.

💻 Muti-step animations

from, to 키워드 말고, 퍼센트를 사용할 수도 있습니다. 이를 통해 두 단계 이상의 애니메이션 효과를 줄 수 있습니다.

퍼센트는 애니메이션의 진척도를 의미합니다. from은 0%의 문법적 설탕(syntactic sugar)이며 to는 100%의 문법적 설탕입니다.

중요한 점은, timing function은 각 단계에 적용된다 라는 사실입니다. 모든 애니메이션에 하나의 ease 효과가 적용되는 것이 아닙니다.

아래의 예시에서, 두개의 스피너는 2초동안 1바퀴를 돕니다. 하지만 multi-step-spin 은 4단계로 구성되어 있으며, 각 단계마다 timing function이 적용되어 있습니다.

불행히도, CSS keyframe 만으로는 위의 동작을 컨트롤 할 수 없습니다. 하지만 Web Animations API를 이용하면 설정할 수 있습니다. 만약 각 단계에서 적용된 ease효과가 문제가 된다면 이 문서를 참고해 보세요.

💻 Alternation animations

수축과 팽창을 하는 '숨쉬는' 효과를 요소에 준다고 가정합시다.

3단계의 애니메이션을 설정할 수 있습니다.

애니메이션 단계의 절반동안은 원래의 크기의 1.5배로 확장 됩니다. 최댓값에 도달하면, 남은 절반동안 원래의 크기로 돌아 갑니다.

위 방법은 동작하지만, 같은 효과를 만들기 위한 더 좋은 방법이 있습니다. animation-direction 속성을 사용하면 됩니다.

animation-direction은 순서를 조정합니다. normal이 기본값이며 0%에서 100%까지 지정한 시간만큼 움직입니다.

흥미로운 점은 alternate 값을 지정할 수 있다는 점입니다. 이 값은 normalreverse 사이를 왔다갔다 하며 반복합니다.

팽창과 수축효과를 하나의 애니메이션에 지정하는 것 보다, 팽창효과만 지정하고 다음 반복시 역으로 진행하게 하면 수축효과를 줄 수 있습니다.

💻 Shorthand values

이 글에서 많은 애니메이션 속성들을 살펴 보았고 이 값들은 모두 입력하기에 너무 많습니다.

transition 과 같이, 모든 속성들은 축약형으로 쓸 수 있습니다. 위 예시는 아래와 같이 쓸 수 있습니다.

.box {
 /*
 animation: grow-and-shrink 2000ms;
 animation-timing-function: ease-in-out;
 animation-iteration-count: infinite;
 animation-direction: alternate;
 */
 
 animation: grow-and-shrink 2000ms ease-in-out infinite alternate;
}

순서는 중요하지 않습니다. 대부분의 경우, 원하는 순서대로 값들을 지정할 수 있습니다. 따라서 순서를 외울필요는 없습니다.

하지만 animation-delay 경우는 예외입니다. 이 값은 지속시간 뒤에 와야합니다. 두 속성 모두 시간을 의미하기 때문입니다.

이 때문에, 이 글을 쓴 필자는 축약형 표현에서 animation-delay 속성을 제외해 따로 선언해 주는 것을 선호합니다.

.box {
 animation: grow-and-shrink 2000ms ease-in-out infinite alternate;
 animation-delay: 500ms;
}

💻 Fill Modes

아마 keyframe 애니메이션 중 가장 헷갈리는 속성일 것입니다.

요소가 사라지는 효과를 주려고 합니다. 아래의 예시에서 애니메이션은 정상동작 하지만, 효과가 끝나면 원래의 상태로 돌아갑니다.

요소의 opacity를 시간에 따른 그래프로 표현한다면 아래와 같이 표현할 수 있습니다.

왜 요소의 가시성이 원래대로 돌아가는 걸까요? fromto 블록 안에 선언된 것들은 애니메이션이 동작할때만 적용됩니다.

1000ms 후에, 애니메이션은 사라지게 됩니다. to 블록안에 선언된 것들은 사라지고, 다른곳에서 선언된 CSS가 적용됩니다. 위 예시에서 다른곳에 opacity 속성을 지정하지 않았기 때문에, 기본값인 1로 돌아갑니다.

이 문제를 해결하기 위한 방법중 하나는 .box 선택자에 opacity 속성을 지정하는 것입니다.

애니메이션이 동작하는 동안, @keyframes 안의 선언문은 .box 선택자 규칙보다 우선순위가 높습니다. 하지만 애니메이션이 끝나게 되면, 애니메이션 안의 선언들은 무효가 되며, .box 선택자 안의 규칙이 적용됩니다.

CSS를 to 블록안의 선언문과 일치하도록 업데이트 할 수 있습니다. 그런데 이 방법이 최선일까요?

✔ Filling forwards

상태를 원래대로 되돌리는 선언을 하는 대신에, animation-fill-mode를 사용해 다른 접근을 해봅시다.

animation-fill-mode를 이용하면 애니메이션의 최종값을 유지할 수 있습니다.

forwards 이름이 혼란스럽지만, 위 그래프를 보면 이해가 될 것 입니다.

애니메이션이 끝나면, animation-fill-mode: forwards 는 마지막 블록의 선언을 복사해 유지하도록 합니다.

✔ Filling backwards

애니메이션 효과가 바로 시작되는 것을 원하지 않을때도 있습니다. transition과 같이 animation-delay로 지연시간을 정할 수 있습니다.

처음 0.5초 동안, 요소는 완전히 보입니다.

fromto 블록안의 CSS는 애니메이션이 동작하는 동안 적용됩니다. animation-delay는 포함되지 않습니다. 따라서 0.5초 동안, from 블록안의 CSS는 적용되지 않습니다.

animation-fill-mode의 또다른 값으로 이 상황을 해결할 수 있습니다. backwards는 애니메이션의 처음 상태를 유지하게 해줍니다.

만약 처음과 끝 상태 모두 유지하려면 어떻게 해야 할까요? 그때는 both라는 값을 사용하면 됩니다.

다른 애니메이션 속성과 마찬가지로 축약형으로 쓸 수 있습니다.

.box {
 animation: slide-in 1000ms ease-out both;
 animation-delay: 500ms;
}

💻 Dynamic aniamtions with CSS variables

튀는 공 효과를 주기 위해, 지금까지 배운 것들을 모두 사용해 봅시다.

CSS 애니메이션은 전역적으로 재사용되게끔 설계되어 있지만, 이 애니메이션은 항상 20px 만큼 튀어 오르게 되어있습니다. 만약 다른 요소들에게 다른 높이를 지정하면 더 멋있지 않을까요?

CSS 변수를 사용하면, 이 부분을 해결할 수 있습니다.

이 방법을 사용하면 애니메이션을 재사용할 수 있습니다.

0개의 댓글