영벨롭 개발 일지

[CSS] CSS Animation 정리와 예제 본문

Front-end/HTML & CSS

[CSS] CSS Animation 정리와 예제

영벨롭 2023. 8. 30. 16:03

📌 CSS Animation

 animation 은 사용자가 어떠한 액션을 취하지 않더라도 스스로 동작하도록 효과를 구현하고자 할 때 사용하는 css 속성입니다. 

 javascript 없이도 여러 상태를 거치며 웹사이트에 다양한 스타일 전환 애니메이션을 적용할 수 있습니다. 

 @keyframes 규칙을 사용하여 애니메이션 세트를 만들고, 이를 animation 에 적용시킬 수 있습니다. 

 

 animation 에는 다음 8가지 속성을 가집니다. 

  • animation-name
  • animation-delay
  • animation-direction
  • animation-fill-mode
  • animation-iteration-count
  • animation-play-state
  • animation-timing-fucntion

 

 animation 은 css 의 단축속성으로 단축형식으로 작성할 수 있습니다. 

 name 은 필수 속성이며, 순서들은 크게 상관 없으나 duration 과 delay 순서는 맞춰야 합니다. 

div {
/* @keyframes duration | easing-function | delay |
iteration-count | direction | fill-mode | play-state | name */
animation: 3s ease-in 1s 2 reverse both paused slidein;

/* @keyframes duration | easing-function | delay | name */
animation: 3s linear 1s slidein;

/* 애니메이션 두 개 */
animation:
  3s linear slidein,
  3s ease-out 5s slideout;
}

📌 animation-name

 @keyframes 에 선언된 애니메이션 이름을 호출하여 적용할 애니메이션을 지정합니다. 

 반드시 @keyframes 에 작성되어 있는 이름이어야 합니다. 

@keyframes 애니메이션이름 { ... }

...
animation-name: 애니메이션이름;
...

📌 animation-delay

 애니메이션이 시작하기 전 지연시간을 지정합니다. 즉, 애니메이션이 시작할 시점을 지정합니다. 

 단위는 s(초) 또는 ms(밀리 초)로 지정할 수 있으며, 양수, 0,  또는 음수 값을 지정할 수 있습니다. 

  • 양수 - 지정된 시간이 경과 한 후 애니메이션 시작
  • 0 (기본값) - 애니메이션 적용 즉시 시작
  • 음수 - 애니메이션이 즉시 시작되지만, 애니메이션 주기의 도중에 시작
/* Single animation */
animation-delay: 3s;
animation-delay: 0s;
animation-delay: -1500ms;

/* Multiple animations */
animation-delay: 2.1s, 480ms;

 


📌 animation-direction

 애니메이션의 방향을 지정합니다.

 normal, reverse, alternate 또는 alternate-reverse 값을 지정할 수 있습니다. 

  • normal (기본값) - 정방향으로 재생
  • reverse - 역방향으로 재생 (e.g. ease-in 타이밍 기능이 ease-out 형태로 변경됨)
  • alternate - 애니메이션이 정방향으로 시작 후, 정방향 & 역방향 번갈아 진행
  • alternate-reverse - 애니메이션이 역방향으로 시작 후, 정방향 & 역방향 번갈아 진행
animation-direction: normal;
animation-direction: reverse;
animation-direction: alternate;
animation-direction: alternate-reverse;

📌 animation-duration

 애니메이션이 한 사이클을 완료하는 데 걸리는 시간을 지정합니다.

 단위는 s(초) 또는 ms(밀리 초)로 지정할 수 있으며, 양수 또는 0 값을 지정할 수 있습니다.

 음수값은 유효하지 않습니다. 

  • 0 (기본값) - 애니메이션이 작동하지 않아야 함
  • 양수 - 한 사이클을 완료하는 데 걸리는 시간 지정
animation-duration: 6s;
animation-duration: 120ms;

📌 animation-fill-mode

 애니메이션의 실행 전과 후에 요소에 스타일을 적용하는 방법을 지정합니다. 

  • none (기본값) - 애니메이션 시작 전 요소에 할당된 스타일 유지
  • forwards - 애니메이션의 마지막 keyframe 에 의해 설정된 스타일 유지
    • 애니메이션 방향 및 반복 수에 따라 다름
  • backwords - 첫 번째 keyframe 에 의해 설정된 스타일을 가져오고, delay 기간 동안 이 값을 유지
    • 애니메이션 방향에 따라 다름
  • both - forwards & backwards 가 동시에 적용
animation-fill-mode: none;
animation-fill-mode: forwards;
animation-fill-mode: backwards;
animation-fill-mode: both;

 


📌 animation-iteration-count

 애니메이션의 사이클 반복 횟수를 지정합니다. 

 숫자 또는 infinite 값을 지정할 수 있습니다. 

  • 숫자 (기본값 1) - 지정한 숫자만큼 사이클 반복
  • infinite - 무한 반복
/* Keyword value */
animation-iteration-count: infinite;

/* <number> values */
animation-iteration-count: 3;
animation-iteration-count: 2.4;

📌 animation-play-state

 애니메이션 동작 상태 여부를 지정합니다. 

 running 또는 paused 값을 지정할 수 있습니다. 

 예를 들어, hover 했을 경우 애니메이션을 실행 또는 정지시키고 싶을 경우 사용합니다. 

  • running (기본값) - 애니메이션 실행
  • paused - 애니메이션 일시 중지
animation-play-state: running;
animation-play-state: paused;

📌 animation-timing-function

 애니메이션의 진행 방식을 지정합니다. 

 기본값은 ease 키워드값이며, transition 속성의 timing-function 에 사용되는 값들과 동일합니다. 

Timing Functions
ease cubic-bezier(0.25, 0.1, 0.25, 1.0) 과 동일
기본 값
속도가 점점 빨라지다가 애니메이션이 진행되는 중간 시점을 기준으로 점점 느려짐
ease-in cubic-bezier(0.42, 0.0, 1.0, 1.0) 과 동일
아주 느리게 시작해서 애니메이션이 진행되면서 속도가 점점 빨라짐
ease-out cubic-bezier(0.0, 0.0, 0.58, 1.0) 과 동일
아주 빠르게 시작해서 속도가 점점 느려짐
ease-in-out cubic-bezier(0.42, 0.0, 0.58, 1.0) 과 동일
ease 와 마찬가지로 속도가 점차 빨라지다가 다시 느려짐
ease 보다 시작 속도가 느림
linear cubic-bezier(0.0, 0.0, 1.0, 1.0) 과 동일
애니메이션이 진행되는 내내 일정한 속도 유지
cubic-bezier(p1, p2, p3, p4) cubic Bezier curve 값을 사용자가 직접 입력 가능
p1, p3 은 반드시 0 과 1 사이의 값이어야 함
p2 가 0보다 작으면 원 애니메이션 방향의 반대로 움직임
p4 가 1보다 크면 의도했던 끝 지점을 뚫고 나감
https://matthewlein.com/tools/ceaser
steps(n, <jumpterm>) 전체 애니메이션 시간을 동일한 간격으로 나누어 정지점을 만드는 timing function
예를 들어 n 이 5이면, 0% ~ 100% 사이에 5개의 구간이 생김
<jumpterm>
: jump-start, jump-end, jump-none, jump-both, start, end
step-start steps(1, jump-start) 와 동일
step-end steps(1, jump-end) 와 동일
/* Keyword values */
animation-timing-function: ease;
animation-timing-function: ease-in;
animation-timing-function: ease-out;
animation-timing-function: ease-in-out;
animation-timing-function: linear;
animation-timing-function: step-start;
animation-timing-function: step-end;

/* Function values */
animation-timing-function: cubic-bezier(0.1, 0.7, 1, 0.1);
animation-timing-function: steps(4, end);

/* Steps Function keywords */
animation-timing-function: steps(4, jump-start);
animation-timing-function: steps(10, jump-end);
animation-timing-function: steps(20, jump-none);
animation-timing-function: steps(5, jump-both);
animation-timing-function: steps(6, start);
animation-timing-function: steps(8, end);

📌 @keyframes

@keyframes 는 애니메이션 중간중간의 특정 지점들을 거칠 수 있는 키프레임들을 설정함으로써 CSS 애니메이션 과정의 중간 절차를 제어할 수 있게 합니다. 

 즉, 애니메이션의 각 지점마다 특정 스타일을 구체적으로 제어할 수 있습니다. 

 

시간에 대한 규칙

  • from / to - from 은 애니메이션 시작 부분, to 는 끝나는 부분
  • % - 0% 는 애니메이션의 시작 부분, 100% 는 끝나는 부분
    • 키 프레임이 여러번 정의 된 경우, 예를 들어 50% 가 두 번 정의된 경우 Cascading 법칙에 따라 아래쪽 속성만 적용됩니다. 
@keyframes slidein {
  from {
    margin-left: 100%;
    width: 300%;
  }

  to {
    margin-left: 0%;
    width: 100%;
  }
}

@keyframes identifier {
  0% {
    top: 0;
    left: 0;
  }
  30% {
    top: 50px;
  }
  68%,
  72% {
    left: 50px;
  }
  100% {
    top: 100px;
    left: 100%;
  }
}

📌 애니메이션 예제

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./animation.css">
    <title>Document</title>
</head>
<body>
    <h1>
        CSS ANIMATION EXAMPLES
    <h1> 

    <h2>Entrances</h2>
    <div class="container">
        <div class="item slide-down">slide-down</div>
        <div class="item slide-up">slide-up</div>
        <div class="item slide-left">slide-left</div>
        <div class="item expand">expand</div>
        <div class="item expand-up">expand-up</div>
        <div class="item fade-in">fade-in</div>
        <div class="item entrance">entrance</div>
    </div>
    
</body>
</html>
h1,
h2 {
  text-align: center;
}

.container {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin: 20px 0;
  width: 100%;
}

.item {
  width: 110px;
  height: 110px;
  border-radius: 10px;
  background-color: orange;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  color: white;
}
/*
==============================================
ANIMATION TIME!!!!
==============================================
*/
/*
==============================================
slideDown
==============================================
*/

@keyframes slideDown {
  0% {
    transform: translateY(-100%);
  }
  50% {
    transform: translateY(8%);
  }
  65% {
    transform: translateY(-4%);
  }
  80% {
    transform: translateY(4%);
  }
  95% {
    transform: translateY(-2%);
  }
  100% {
    transform: translateY(0%);
    background-color: blue;
  }
}

/* animation: 
name duration timing-function delay iteration-count direction fill-mode; */
.slide-down {
  /* animation: slideDown 2s ease 0.5s 1 normal forwards; */
  animation-name: slideDown;
  animation-duration: 2s;
  animation-timing-function: ease;
  animation-delay: 0.5s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
}
/*
==============================================
slideUp
==============================================
*/

@keyframes slideUp {
  0% {
    transform: translateY(100%);
    background-color: red;
  }
  50% {
    transform: translateY(-8%);
  }
  65% {
    transform: translateY(4%);
  }
  80% {
    transform: translateY(-4%);
  }
  95% {
    transform: translateY(2%);
  }
  100% {
    transform: translateY(0%);
  }
}

.slide-up {
  /* animation: slideUp 2s ease 3s 1 normal backwards; */
  animation-name: slideUp;
  animation-duration: 2s;
  animation-timing-function: ease;
  animation-delay: 3s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: backwards;
}

/*
==============================================
slideLeft
==============================================
*/

@keyframes slideLeft {
  0% {
    transform: translateX(150%);
    background-color: red;
  }
  50% {
    transform: translateX(-8%);
  }
  65% {
    transform: translateX(4%);
  }
  80% {
    transform: translateX(-4%);
  }
  95% {
    transform: translateX(2%);
  }
  100% {
    transform: translateX(0%);
    background-color: blue;
  }
}

.slide-left {
  /* animation: slideLeft 2s ease 3s 1 normal both; */
  animation-name: slideLeft;
  animation-duration: 2s;
  animation-timing-function: ease;
  animation-delay: 3s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: both;
}

/*
==============================================
slideExpandUp
==============================================
*/

@keyframes slideExpandUp {
  0% {
    transform: translateY(100%) scaleX(0.5);
  }
  30% {
    transform: translateY(-8%) scaleX(0.5);
  }
  40% {
    transform: translateY(2%) scaleX(0.5);
  }
  50% {
    transform: translateY(0%) scaleX(1.1);
  }
  60% {
    transform: translateY(0%) scaleX(0.9);
  }
  70% {
    transform: translateY(0%) scaleX(1.05);
  }
  80% {
    transform: translateY(0%) scaleX(0.95);
  }
  90% {
    transform: translateY(0%) scaleX(1.02);
  }
  100% {
    transform: translateY(0%) scaleX(1);
  }
}

.expand {
  /* animation: slideExpandUp 2s ease 0s 1 normal normal; */
  animation-name: slideExpandUp;
  animation-duration: 2s;
  animation-timing-function: ease;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: normal;
}

/*
==============================================
expandUp
==============================================
*/

@keyframes expandUp {
  0% {
    transform: translateY(100%) scale(0.6) scaleY(0.5);
  }
  60% {
    transform: translateY(-7%) scaleY(1.12);
  }
  75% {
    transform: translateY(3%);
  }
  100% {
    transform: translateY(0%) scale(1) scaleY(1);
  }
}

.expand-up {
  /* animation: expandUp 2s ease 0s 1 normal normal; */
  animation-name: expandUp;
  animation-duration: 2s;
  animation-timing-function: ease;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: normal;
}
/*
==============================================
fadeIn
==============================================
*/

@keyframes fadeIn {
  0% {
    transform: scale(0);
    opacity: 0;
  }
  60% {
    transform: scale(1.1);
  }
  80% {
    transform: scale(0.9);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

.fade-in {
  /* animation: fadeIn 2s ease 0s 1 normal normal; */
  animation-name: fadeIn;
  animation-duration: 2s;
  animation-timing-function: ease;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: normal;
}

/*
==============================================
bigEntrance
==============================================
*/

@keyframes bigEntrance {
  0% {
    transform: scale(0.3) rotate(6deg) translateX(-30%) translateY(30%);
    opacity: 0.2;
  }
  30% {
    transform: scale(1.03) rotate(-2deg) translateX(2%) translateY(-2%);
    opacity: 1;
  }
  45% {
    transform: scale(0.98) rotate(1deg) translateX(0%) translateY(0%);
    opacity: 1;
  }
  60% {
    transform: scale(1.01) rotate(-1deg) translateX(0%) translateY(0%);
    opacity: 1;
  }
  75% {
    transform: scale(0.99) rotate(1deg) translateX(0%) translateY(0%);
    opacity: 1;
  }
  90% {
    transform: scale(1.01) rotate(0deg) translateX(0%) translateY(0%);
    opacity: 1;
  }
  100% {
    transform: scale(1) rotate(0deg) translateX(0%) translateY(0%);
    opacity: 1;
  }
}

.entrance {
  /* animation: bigEntrance 2s ease 0s 1 normal normal; */
  animation-name: bigEntrance;
  animation-duration: 2s;
  animation-timing-function: ease;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: normal;
}
반응형