[CSS] CSS Animation 정리와 예제
📌 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;
}