β›³

ch3 - 3. Keyframe

Index


0. File download


1. Keyframe

1.1 Keyframe에 λŒ€ν•˜μ—¬

@keyframes에 λŒ€ν•˜μ—¬ κ°€λ²Όμš΄ 예제λ₯Ό 보고 가도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <style> /* ν‚€ν”„λ ˆμž„ 이름 == μ• λ‹ˆλ©”μ΄μ…˜ 이름 */ @keyframes hojun { 0% { transform: translate(0, 0); } 100% { transform: translate(300px, 0) rotate(360deg) scale(2); } } div { margin: 200px; width: 100px; height: 100px; background-color: red; animation: hojun 1s; } </style> </head> <body> <div>hello world</div> </body> </html>
ν•΄λ‹Ή @keyframes hojun을 μ„€μ •ν•˜μ—¬ div의 animation으둜 1μ΄ˆκ°„κ²©μœΌλ‘œ μ£Όλ©΄ μ•„λž˜μ™€ 같이 μ‹€ν–‰λ˜κ²Œ λ©λ‹ˆλ‹€.
notion imagenotion image
이처럼 Keyframe은 μ–΄λ–€ λ³€ν™”κ°€ μΌμ–΄λ‚˜λŠ” 지점을 μ„€μ •ν•˜μ—¬ νŠΉμ • μ‹œκ°„ λ™μ•ˆ ν•΄λ‹Ή Property와 Valueλ₯Ό λ³€ν™”μ‹œν‚΅λ‹ˆλ‹€.
+ transitionκ³Ό animation의 차이점 transitionκ³Ό animation 속성은 Javascript의 도움 없이 μ˜€λΈŒμ νŠΈμ— 직접 μ• λ‹ˆλ©”μ΄μ…˜ 효과λ₯Ό μ μš©ν•  λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€. transitionκ³Ό animation은 μš”μ†Œ μƒνƒœμ— λŒ€ν•œ 의쑴 여뢀에 λŒ€ν•΄ 차이λ₯Ό κ°€μ§‘λ‹ˆλ‹€. transition은 μš”μ†Œμ˜ μƒνƒœκ°€ λ³€κ²½λ˜μ–΄μ•Ό μ• λ‹ˆλ©”μ΄μ…˜μ„ μ‹€ν–‰ν•  수 μžˆμ§€λ§Œ, animation 속성은 μš”μ†Œμ˜ μƒνƒœ 변화와 관계없이 μ• λ‹ˆλ©”μ΄μ…˜μ„ μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ animation 속성은 @keyframes 속성을 μ΄μš©ν•΄ ν”„λ ˆμž„μ„ μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

1.2. Keyframe κ·œμΉ™

@keyframes은 μ• λ‹ˆλ©”μ΄μ…˜μ΄ λ§Œλ“€μ–΄μ§€λŠ” λΆ€λΆ„μž…λ‹ˆλ‹€. from μ†μ„±μ΄λ‚˜ 0% 속성에 μ„€μ •ν•œ μŠ€νƒ€μΌλΆ€ν„° to μ†μ„±μ΄λ‚˜ 100% 속성에 μ„€μ •ν•œ μŠ€νƒ€μΌλ‘œ 점차 λ³€κ²½λ˜λ©΄μ„œ μ• λ‹ˆλ©”μ΄μ…˜μ΄ μž¬μƒλ©λ‹ˆλ‹€. 0%κ³Ό 100% μ‚¬μ΄μ—λŠ” μ—¬λŸ¬ 개의 쀑간 속성을 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
/* [ from ~ to 속성 ] */ @keyframes animation-name { /* μ• λ‹ˆλ©”μ΄μ…˜μ˜ μ‹œμž‘ ν”„λ ˆμž„ */ from { styles; } /* μ• λ‹ˆλ©”μ΄μ…˜μ˜ μ’…λ£Œ ν”„λ ˆμž„ */ to { styles; } /* [ 0% ~ 100% 속성 ] */ @keyframes animation-name { /* μ• λ‹ˆλ©”μ΄μ…˜μ˜ μ‹œμž‘ ν”„λ ˆμž„ */ 0% { styles; } 50% { styles; } /* μ• λ‹ˆλ©”μ΄μ…˜μ˜ μ’…λ£Œ ν”„λ ˆμž„ */ 100% { styles; }

1.3 Animation μ μš©ν•˜κΈ°

CSS3 μ• λ‹ˆλ©”μ΄μ…˜μ„ μ΄μš©ν•˜λ©΄ μ—¬λŸ¬ 개의 CSS μŠ€νƒ€μΌμ„ λΆ€λ“œλŸ½κ²Œ μ „ν™˜μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€. @keyframes은 CSS μŠ€νƒ€μΌμ˜ λ³€ν™” 과정을 λ‚˜νƒ€λ‚Ό λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€. @keyframes을 μ΄μš©ν•œ μ• λ‹ˆλ©”μ΄μ…˜μ€ @transition보닀 μ •λ°€ν•œ 효과λ₯Ό κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

1.3.1 animation의 단일 속성듀

  • animation-name μ• λ‹ˆλ©”μ΄μ…˜μ„ μž¬μƒ(호좜) ν•˜κΈ° μœ„ν•΄μ„œλŠ” λ°˜λ“œμ‹œ 이름을 μ •μ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€. name은 @keyframes μ†μ„±μ—μ„œ μ„€μ •ν•œ 이름을 λ™μΌν•˜κ²Œ μ‚¬μš©ν•©λ‹ˆλ‹€.
/* ν‚€ν”„λ ˆμž„ 이름 == μ• λ‹ˆλ©”μ΄μ…˜ 이름 */ @keyframes yoon { 0% { styles; } 100% { styles; } } div{ /* μ• λ‹ˆλ©”μ΄μ…˜ 이름 */ animation-name: yoon; }
+ animation-name 이름 κ·œμΉ™ animation-name의 μ‹œμž‘μ—λŠ” 영문 μ†Œλ¬Έμž, 숫자, λ¬Έμžμ—΄, 언더바(_), ν•˜μ΄ν”ˆ(-)을 μ‚¬μš©ν•©λ‹ˆλ‹€. 영문 λŒ€λ¬Έμž, 숫자, νŠΉμˆ˜λ¬ΈμžλŠ” μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€(파일 및 폴더λͺ…μ—λŠ” ν—ˆμš©). μ—¬λŸ¬ 개의 animation-name을 λ™μ‹œμ— λ‚˜μ—΄ν•  경우 ,λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
/* [ μ˜¬λ°”λ₯Έ 이름 μ˜ˆμ‹œ ] */ animation-name: yoon; /* 영문 μ†Œλ¬Έμžλ‘œ μ‹œμž‘ν•˜λŠ” 이름 */ animtaion-name: _yoon; /* 언더바(_)둜 μ‹œμž‘ν•˜λŠ” 이름 */ animation-name: -yoon; /* ν•˜μ΄ν”ˆ(-)으둜 μ‹œμž‘ν•˜λŠ” 이름 */ animation-name: yoon1, yoon2; /* μ—¬λŸ¬ 개의 animation-name λ‚˜μ—΄ */ /* [ 잘λͺ»λœ 이름 μ˜ˆμ‹œ ] */ animation-name: Name-yoon; /* 영문 λŒ€λ¬Έμžλ‘œ μ‹œμž‘ν•˜λŠ” 이름 */ animation-name: *-name-yoon; /* 특수문자둜 μ‹œμž‘ν•˜λŠ” 이름 */ animation-name: 1yoon; /* 숫자둜 μ‹œμž‘ν•˜λŠ” 이름 */
  • animation-duration duration 속성은 μ• λ‹ˆλ©”μ΄μ…˜μ˜ μ‹œμž‘λΆ€ν„° μ’…λ£ŒκΉŒμ§€μ˜ 총 지속 μ‹œκ°„μ„ μ„€μ •ν•  λ•Œ μ‚¬μš©ν•˜λ©°, transition-durationκ³Ό μœ μ‚¬ν•œ κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. duration 값은 μ–‘μˆ˜λ‘œ 지정해야 κ·Έ κ²°κ³Όλ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. 속성 값을 0 ν˜Ήμ€ 음수둜 μ„€μ •ν–ˆμ„ 경우 μ• λ‹ˆλ©”μ΄μ…˜μ΄ μ‹€ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
/* [ μ• λ‹ˆλ©”μ΄μ…˜μ΄ μž¬μƒλ˜μ§€ μ•ŠλŠ” 경우 ] */ animation-duration: 0; /* μž¬μƒμ‹œκ°„μ΄ 0인 경우 */ animation-duration: -3s; /* μž¬μƒμ‹œκ°„μ΄ 음수인 경우 */ /* [ μ• λ‹ˆλ©”μ΄μ…˜μ΄ μž¬μƒλ˜λŠ” 경우 ] */ animation-duration: 3s; /* μž¬μƒμ‹œκ°„μ΄ μ–‘μˆ˜μΈ 경우 */ animation-duration: 500ms; /* 1초 μ΄ν•˜μ˜ μž¬μƒμ‹œκ°„μ„ μž…λ ₯ν•  경우 */
duration μ†μ„±μ˜ κ²°κ³ΌλŠ” μ•„λž˜μ˜ 전체 μ½”λ“œλ₯Ό 톡해 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <style> @keyframes yoon { from {transform: translate(100px, 0);} to {transform: translate(300px, 0);} } div { position: absolute; margin: 50px; width: 100px; height: 100px; background-color: #ff0000; /* μ• λ‹ˆλ©”μ΄μ…˜ 이름 */ animation-name: yoon; } /* [ μž¬μƒμ‹œκ°„μ΄ 0인 경우 ] */ .duration_0s { top: 20px; animation-duration: 0; } /* [ μž¬μƒμ‹œκ°„μ΄ 음수인 경우 ] */ .duration_minus { top: 130px; animation-duration: -3s; } /* [ μž¬μƒμ‹œκ°„μ΄ μ–‘μˆ˜μΈ 경우 ] */ .duration_plus { top: 240px; animation-duration: 3s; } /* [ 1초 μ΄ν•˜μ˜ μž¬μƒμ‹œκ°„μ„ μž…λ ₯ν•  경우 ] */ .duration_ms { top: 350px; animation-duration: 500ms; } </style> </head> <body> <div class="duration_0s">0s</div> <div class="duration_minus">minus</div> <div class="duration_plus">plus</div> <div class="duration_ms">ms</div> </body> </html>
  • animation-iteration-count μœ„μ˜ duration μ½”λ“œ 예제λ₯Ό μ‹€ν–‰μ‹œν‚€λ©΄ μ• λ‹ˆλ©”μ΄μ…˜μ΄ 1회 μž¬μƒ ν›„ μ’…λ£Œλ˜λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. iteration-count 속성은 μ• λ‹ˆλ©”μ΄μ…˜μ„ μž¬μƒν•˜λŠ” 횟수λ₯Ό 지정할 λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€. iteration-count μ†μ„±μ˜ κΈ°λ³Έ 값은 1이며, 0으둜 값을 지정할 경우 μ• λ‹ˆλ©”μ΄μ…˜μ΄ μž¬μƒλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 음수둜 속성 값을 지정할 경우 κΈ°λ³Έ 값인 1κ³Ό 같은 κ²°κ³Όλ₯Ό 좜λ ₯ν•˜κ³ , μžμ—°μˆ˜κ°€ μ•„λ‹Œ μ–‘μ˜ 유리수(ex. 1.5)둜 속성 값을 지정할 경우 μ• λ‹ˆλ©”μ΄μ…˜ μž¬μƒ 도쀑 첫 번째 ν”„λ ˆμž„μœΌλ‘œ λŒμ•„κ°€ μ’…λ£Œλ©λ‹ˆλ‹€. infinite둜 값을 μ„€μ •ν•  경우 μ• λ‹ˆλ©”μ΄μ…˜μ„ λ¬΄ν•œ λ°˜λ³΅ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
/* [ μ• λ‹ˆλ©”μ΄μ…˜μ΄ μž¬μƒλ˜μ§€ μ•ŠλŠ” 경우 ] */ animation-iteration-count: 0; /* μž¬μƒνšŸμˆ˜κ°€ 0인 경우 */ animation-iteration-count: -3; /* μž¬μƒνšŸμˆ˜κ°€ 음수인 경우 */ /* [ μ• λ‹ˆλ©”μ΄μ…˜μ΄ μž¬μƒλ˜λŠ” 경우 ] */ animation-iteration-count: 3; /* μž¬μƒνšŸμˆ˜κ°€ μ–‘μˆ˜μΈ 경우 */ animation-iteration-count: 1.5; /* μž¬μƒνšŸμˆ˜κ°€ μ‹€μˆ˜μΈ 경우 */ animation-iteration-count: infinite; /* μ• λ‹ˆλ©”μ΄μ…˜μ„ λ¬΄ν•œ λ°˜λ³΅ν•  경우 */
iteration-count μ†μ„±μ˜ κ²°κ³ΌλŠ” μ•„λž˜μ˜ 전체 μ½”λ“œλ₯Ό 톡해 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <style> @keyframes yoon { from {transform: translate(100px, 0);} to {transform: translate(300px, 0);}} div { position: absolute; margin: 50px; width: 100px; height: 100px; background-color: #ff0000; /* μ• λ‹ˆλ©”μ΄μ…˜ 속성 */ animation-name: yoon; animation-duration: 1s; } /* [ μž¬μƒνšŸμˆ˜κ°€ 0인 경우 ] */ .iteration-count_0 { top: 20px; animation-iteration-count: 0; } /* [ μž¬μƒνšŸμˆ˜κ°€ 음수인 경우 ] */ .iteration-count_minus { top: 130px; animation-iteration-count: -3; } /* [ μž¬μƒνšŸμˆ˜κ°€ μ–‘μˆ˜μΈ 경우 ] */ .iteration-count_plus { top: 240px; animation-iteration-count: 3; } /* [ μž¬μƒνšŸμˆ˜κ°€ 유리수인 경우 ] */ .iteration-count_rational { top: 350px; animation-iteration-count: 1.5; } /* [ μ• λ‹ˆλ©”μ΄μ…˜μ„ λ¬΄ν•œ λ°˜λ³΅ν•  경우 ] */ .iteration-count_infinite { top: 460px; animation-iteration-count: infinite; } </style> </head> <body> <div class="iteration-count_0">0</div> <div class="iteration-count_minus">minus</div> <div class="iteration-count_plus">plus</div> <div class="iteration-count_rational">rational</div> <div class="iteration-count_infinite">infinite</div> </body> </html>
  • animation-direction μ• λ‹ˆλ©”μ΄μ…˜μ˜ μž¬μƒ λ°©ν–₯을 μ„€μ •ν•  λ•Œ direction 속성을 μ‚¬μš©ν•©λ‹ˆλ‹€. direction μ†μ„±μ˜ κΈ°λ³Έ 값은 from λ˜λŠ” 0%에 μ„€μ •λœ μŠ€νƒ€μΌμ—μ„œ toλ˜λŠ”100%에 μ„€μ •λœ μŠ€νƒ€μΌλŒ€λ‘œ μž¬μƒν•˜λŠ” normal μž…λ‹ˆλ‹€. direction μ†μ„±μ˜ μ’…λ₯˜λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
animation-direction: normal; /* 순방ν–₯ μž¬μƒ */ animation-direction: reverse; /* μ—­λ°©ν–₯ μž¬μƒ */ animation-direction: alternate; /* 순방ν–₯ μ‹œμž‘, 순방ν–₯-μ—­λ°©ν–₯ λ²ˆκ°ˆμ•„ μž¬μƒ */ animation-direction: alternate-reverse; /* μ—­λ°©ν–₯ μ‹œμž‘, μ—­λ°©ν–₯-순방ν–₯ λ²ˆκ°ˆμ•„ μž¬μƒ */
alternate와 alternate-reverseλŠ” μ„œλ‘œ λ°˜λŒ€μ˜ κ²°κ³Όλ₯Ό λ³΄μ—¬μ€λ‹ˆλ‹€. alternate은 순방ν–₯으둜 μ• λ‹ˆλ©”μ΄μ…˜μ„ μ‹œμž‘ν•΄ μ‹€ν–‰ νšŸμˆ˜κ°€ ν™€μˆ˜μΌ λ•Œμ—λŠ” 순방ν–₯으둜, 짝수일 λ•Œμ—λŠ” μ—­λ°©ν–₯으둜 μž¬μƒν•©λ‹ˆλ‹€. 반면, alternate-reverse은 μ—­λ°©ν–₯으둜 μ• λ‹ˆλ©”μ΄μ…˜μ„ μ‹œμž‘ν•΄ μ‹€ν–‰ νšŸμˆ˜κ°€ ν™€μˆ˜μΌ λ•Œμ—λŠ” μ—­λ°©ν–₯으둜, 짝수 일 λ•Œμ—λŠ” 순방ν–₯으둜 μž¬μƒν•©λ‹ˆλ‹€. direction μ†μ„±μ˜ κ²°κ³ΌλŠ” μ•„λž˜μ˜ 전체 μ½”λ“œμ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <style> @keyframes yoon { from {transform: translate(100px, 0);} to {transform: translate(300px, 0);}} div { position: absolute; margin: 50px; width: 100px; height: 100px; background-color: #ff0000; /* μ• λ‹ˆλ©”μ΄μ…˜ 속성 */ animation-name: yoon; animation-duration: 1s; animation-iteration-count: infinite;} /* [ 순방ν–₯ μž¬μƒ ] */ .direction_normal { top: 20px; animation-direction: normal;} /* [ μ—­λ°©ν–₯ μž¬μƒ ] */ .direction_reverse { top: 130px; animation-direction: reverse} /* [ 순방ν–₯ μ‹œμž‘, 순방ν–₯-μ—­λ°©ν–₯ λ²ˆκ°ˆμ•„ μž¬μƒ ] */ .direction_alternate { top: 240px; animation-direction: alternate;} /* [ μ—­λ°©ν–₯ μ‹œμž‘, μ—­λ°©ν–₯-순방ν–₯ λ²ˆκ°ˆμ•„ μž¬μƒ ] */ .direction_alternate-reverse { top: 350px; animation-direction: alternate-reverse;} </style> </head> <body> <div class="direction_normal">normal</div> <div class="direction_reverse">reverse</div> <div class="direction_alternate">alternate</div> <div class="direction_alternate-reverse">alternate-reverse</div> </body> </html>
  • animation-timing-function timing-function은 μ• λ‹ˆλ©”μ΄μ…˜ @keyframes μ‚¬μ΄μ˜ μž¬μƒ 속도λ₯Ό μ‘°μ ˆν•˜λŠ” μ†μ„±μœΌλ‘œ, transion-timing-function 속성과 μœ μ‚¬ν•œ κ²°κ³Όλ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. timing-function μ†μ„±μ˜ μ’…λ₯˜λ‘œλŠ” ease, linear, ease-in, ease-out, ease-in-out, cubic-bezier(n, n, n, n) 등이 μžˆμŠ΅λ‹ˆλ‹€.
[ 같은 μ• λ‹ˆλ©”μ΄μ…˜ κ²°κ³Όλ₯Ό 좜λ ₯ν•˜λŠ” 속성값 ] animation-timing-function: ease; /* κΈ°λ³Έκ°’ */ animation-timing-function: cubic-bazier(0,25, 0.1, 0.25, 1); animation-timing-function: linear; animation-timing-function: cubic-bazier(0,0,1,1); animation-timing-function: ease-in; animation-timing-function: cubic-bazier(0.42,0,1,1); animation-timing-function: ease-out; animation-timing-function: cubic-bazier(0,0,0.58,1); animation-timing-function: ease-in-out; animation-timing-function: cubic-bazier(0.42,0,0.58,1);
각 속성값에 λŒ€ν•œ 속도 κ·Έλž˜ν”„λŠ” λ‹€μŒκ³Ό κ°™μœΌλ©°, cubic-bezier의 n 값에 λ”°λ₯Έ λ³€ν™”λŠ” https://cubic-bezier.com/ μ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
notion imagenotion image
  • animation-delay μ• λ‹ˆλ©”μ΄μ…˜ μ‹œμž‘μ„ μ§€μ—°μ‹œν‚€κ³  싢을 경우, delay 속성을 μ‚¬μš©ν•©λ‹ˆλ‹€. delay μ†μ„±μ˜ κΈ°λ³Έ 값은 μ• λ‹ˆλ©”μ΄μ…˜μ΄ 지연 없이 μ‹œμž‘λ˜λŠ” 0 λ˜λŠ” nowμž…λ‹ˆλ‹€. 값이 음수일 경우 μ§€μ •λœ μ‹œκ°„μ΄ μ§€λ‚œ λ’€μ˜ μž₯λ©΄λΆ€ν„° 지연 없이 μ• λ‹ˆλ©”μ΄μ…˜μ΄ μ‹œμž‘λ©λ‹ˆλ‹€.
animation-delay: 0; /* λ°”λ‘œ μž¬μƒ */ animation-delay: now; /* λ°”λ‘œ μž¬μƒ */ animation-delay: 1.5s; /* 지연 μž¬μƒ */ animation-delay: -500ms; /* 지정 μ‹œκ°„ 이후 ν”„λ ˆμž„λΆ€ν„° λ°”λ‘œ μž¬μƒ */
delay μ†μ„±μ˜ κ²°κ³ΌλŠ” μ•„λž˜μ˜ 전체 μ½”λ“œμ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <style> @keyframes yoon { from {transform: translate(100px, 0)} to {transform: translate(300px, 0);}} div { position: absolute; margin: 50px; width: 100px; height: 100px; background-color: #ff0000; /* μ• λ‹ˆλ©”μ΄μ…˜ 속성 */ animation-name: yoon; animation-duration: 1s; animation-iteration-count: 1;} /* [ λ°”λ‘œ μž¬μƒ ] */ .delay_0 { top: 20px; animation-delay: 0;} /* [ λ°”λ‘œ μž¬μƒ ] */ .delay_now { top: 130px; animation-delay: now;} /* [ 지연 μž¬μƒ ] */ .delay_plus { top: 240px; animation-delay: 1.5s;} /* [ 지정 μ‹œκ°„ 이후 ν”„λ ˆμž„λΆ€ν„° λ°”λ‘œ μž¬μƒ ] */ .delay_minus { top: 350px; animation-delay: -500ms;} </style> </head> <body> <div class="delay_0">0</div> <div class="delay_now">now</div> <div class="delay_plus">plus</div> <div class="delay_minus">minus</div> </body> </html>
  • animation-play-state μž¬μƒμ—¬λΆ€λ₯Ό μ„€μ •ν•  경우 play-state 속성을 μ‚¬μš©ν•©λ‹ˆλ‹€. 속성값이 running일 경우 μ• λ‹ˆλ©”μ΄μ…˜μ„ μž¬μƒν•˜κ³ , paused일 경우 μ• λ‹ˆλ©”μ΄μ…˜μ„ μ •μ§€ν•©λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="http://code.jquery.com/jquery-3.2.0.min.js"></script> <script type="text/javascript"> $(function () { $('.play').click(function () { $('div').css('animation-play-state', 'running'); }); $('.stop').click(function () { $('div').css('animation-play-state', 'paused'); }); }); </script> <style> @keyframes yoon { from { transform: translate(100px, 0); } to { transform: translate(300px, 0); } } div { position: absolute; margin: 50px; width: 100px; height: 100px; background-color: #ff0000; /* μ• λ‹ˆλ©”μ΄μ…˜ 속성 */ animation-name: yoon; animation-duration: 2s; animation-iteration-count: infinite; } </style> </head> <body> <button class="play">running</button> <button class="stop">paused</button> <div>box</div> </body> </html>

2. μ‹€ν–‰ν•΄ 보며 λ°°μš°λŠ” Keyframe 예제

2.1 λΉŒλ”© 올리기

μ•„λž˜ 예제(002.html)λŠ” keyframesλ₯Ό μ΄μš©ν•˜μ—¬ background 이미지λ₯Ό animation stepsλ₯Ό μ΄μš©ν•˜μ—¬ 순차적으둜 μ˜†μœΌλ‘œ λ„˜κΈ°λ©° 마치 λΉŒλ”©μ΄ μ§€μ–΄μ§€λŠ” κ²ƒμ²˜λŸΌ 보이게 ν•˜λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <style> @keyframes hojun { from{ background-position: 0px, 0px; } to { background-position: -3730px, 0; } } .building1{ width: 110px; height: 180px; background: url(./animation/building/building1.png) no-repeat; animation: hojun 5s steps(33); animation-fill-mode: forwards; } </style> </head> <body> <div class="building1"></div> </body> </html>
이 예제λ₯Ό μ‹€ν–‰μ‹œν‚€λ©΄ μ•„λž˜μ™€ 같은 이미지가 순차적으둜 5초의 μ‹œκ°„ 간격을 가지고 μ„Έμ›Œμ§€λŠ” κ²ƒμ²˜λŸΌ λ³΄μ΄λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.
notion imagenotion image
이 μ½”λ“œμ—μ„œ fromκ³Ό toλŠ” 0%와 100%μž…λ‹ˆλ‹€. μ—¬κΈ°μ„œ background-position: -3730px, 0 값이 to에 μžˆλŠ” μ΄μœ λŠ” 이미지가 μ™Όμͺ½ 상단에 0, 0μ—μ„œ μ˜†μœΌλ‘œ ν•˜λ‚˜μ˜ μž₯면이 λ„˜μ–΄κ°€λ©° μ΄λ―Έμ§€μ˜ Position은 κ²°κ΅­ λ§ˆμ΄λ„ˆμŠ€μ˜ 값을 κ°€μ§€κ²Œ 되기 λ•Œλ¬Έμž…λ‹ˆλ‹€.
또, animation: hojun 5s steps(33);에 μŠ€νƒ­μ΄ μžˆλŠ” μ΄μœ λŠ” 이미지가 λΆ€λ“œλŸ½κ²Œ μ˜†μœΌλ‘œ λ„˜μ–΄κ°€λŠ” 것이 μ•„λ‹ˆλΌ 각각의 μž₯면이 λŠμ–΄μ§€λ©΄μ„œ 건물을 λ³΄μ—¬μ€˜μ•Ό ν•˜κΈ° λ•Œλ¬Έμ— κ·Έλ ‡μŠ΅λ‹ˆλ‹€.

2.2 λΉŒλ”© 2개 올리기

μ•„λž˜ 예제(003.html)λŠ” μœ„μ™€ 같은 λ°©μ‹μœΌλ‘œ 2개의 건물을 μ˜¬λ¦¬λŠ” μ½”λ“œμž…λ‹ˆλ‹€. μ—¬κΈ°μ„œ background-position에 λ§ˆμ΄λ„ˆμŠ€ 값은 μ΄λ―Έμ§€μ˜ κΈΈμ΄μž…λ‹ˆλ‹€. μŠ€νƒ­μ€ 총 넓이λ₯Ό 각각의 이미지에 건물 이미지 넓이λ₯Ό λ‚˜λˆˆ κ°’μž…λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <style> @keyframes one { from{ background-position: 0px, 0px; } to { background-position: -3730px, 0; } } @keyframes two { from{ background-position: 0px, 0px; } to { background-position: -5346px, 0; } } .building1{ width: 110px; height: 180px; background: url(./animation/building/building1.png) no-repeat; animation: one 5s steps(33); animation-fill-mode: forwards; } .building2{ width: 165px; height: 180px; background: url(./animation/building/building2.png) no-repeat; animation: two 5s steps(32); animation-fill-mode: forwards; transform: translate(300px, 300px); } </style> </head> <body> <div class="building1"></div> <div class="building2"></div> </body> </html>

2.3 λΉŒλ”© 3κ°œμ™€ λƒ₯μ΄μ§‘μ‚¬λ‹˜ 배치

μ΄λ²ˆμ—λŠ” 주인곡인 λƒ₯이 μ§‘μ‚¬λ‹˜μ„ λ°°μΉ˜ν•΄λ³΄λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€. μ’€ 더 자유둜운 포지셔닝을 μœ„ν•΄ htmlμ½”λ“œλŠ” μ•„λž˜μ™€ 같이 λ°°μΉ˜ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
<div class="back"> <div class="cat"></div> <div class="building1"></div> <div class="building2"></div> <div class="building7"></div> </div>
μ—¬κΈ°μ„œ back classμ—λŠ” relative 속성을 μ£Όκ³  κ·Έ μ•„λž˜ μžˆλŠ” divλŠ” absolute 속성을 λΆ€μ—¬ν•˜μ—¬ 자유둜운 λ°°μΉ˜κ°€ κ°€λŠ₯ν•˜λ„λ‘ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
@keyframes cat { 33.3% { transform: translateY(0) scale(0.3); background: url(./animation/cat/1.png) no-repeat; } 66.6% { transform: translateX(-100px) scale(0.3); background: url(./animation/cat/2.png) no-repeat; } 100% { transform: translateX(-200px) scale(0.3); background: url(./animation/cat/3.png) no-repeat; } }
animation λΆ€λΆ„λ§Œ ν•œ 번 보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€. backgroundμ—μ„œ 이미지 3개λ₯Ό κ΅μ²΄ν•¨μœΌλ‘œ 마치 λƒ₯이 μ§‘μ‚¬λ‹˜μ΄ κ±·λŠ” κ²ƒμ²˜λŸΌ κ΅¬ν˜„ν•˜λ € ν•˜μ˜€μŠ΅λ‹ˆλ‹€. 여기에 λƒ₯이 μ§‘μ‚¬λ‹˜μ΄ κ±Έμ–΄μ•Ό ν•˜λ―€λ‘œ YμΆ•μœΌλ‘œ 이동을 ν•˜κ²Œ ν•˜μ˜€κ³ , λƒ₯이 μ§‘μ‚¬λ‹˜μ˜ λͺΈμ§‘이 λ„ˆλ¬΄ μ»€μ„œ scale(0.3) 의 속성을 λΆ€μ—¬ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
μ•„λž˜ μ½”λ“œλŠ” λͺ¨λ“  μ½”λ“œμž…λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <style> body, img, div{ padding: 0; margin: 0; } @keyframes one { from{ background-position: 0px, 0px; } to { background-position: -3730px, 0; } } @keyframes two { from{ background-position: 0px, 0px; } to { background-position: -5346px, 0; } } @keyframes seven { from{ background-position: 0px, 0px; } to { background-position: -3300px, 0; } } @keyframes cat { 33.3% { transform: translateY(0) scale(0.3); background: url(./animation/cat/1.png) no-repeat; } 66.6% { transform: translateX(-100px) scale(0.3); background: url(./animation/cat/2.png) no-repeat; } 100% { transform: translateX(-200px) scale(0.3); background: url(./animation/cat/3.png) no-repeat; } } .building1{ width: 110px; height: 180px; background: url(./animation/building/building1.png) no-repeat; animation: one 5s steps(33); animation-fill-mode: forwards; transform: scale(0.5); position: absolute; top: 10px; left: 10px; } .building2{ width: 165px; height: 180px; background: url(./animation/building/building2.png) no-repeat; animation: two 5s steps(32); animation-fill-mode: forwards; transform: scale(0.5); position: absolute; top: 300px; left: 300px; } .building7{ width: 150px; height: 180px; background: url(./animation/building/building7.png) no-repeat; animation: seven 5s steps(22); animation-fill-mode: forwards; position: absolute; top: 170px; left: 150px; } .cat{ width: 313px; height: 436px; background: url(./animation/cat.png) no-repeat; animation: cat .5s infinite; transform: scale(0.3); position: absolute; top: 10px; left: 600px; } .back{ width: 100vw; height: 150vh; background-color: YellowGreen; position: relative; } </style> </head> <body> <div class="back"> <div class="cat"></div> <div class="building1"></div> <div class="building2"></div> <div class="building7"></div> </div> </body> </html>

2.4 λΉŒλ”© 3κ°œμ™€ λƒ₯μ΄μ§‘μ‚¬λ‹˜ κ±·κ²Œν•˜κΈ°

λ‹€μŒ νŒŒμΌμ€(006.html) μœ„ νŒŒμΌμ—μ„œ λƒ₯이 μ§‘μ‚¬λ‹˜μ΄ μ’€ 더 ν˜„μ‹€μ μœΌλ‘œ 걷게 ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€. %λ₯Ό 10%둜 λ‚˜λˆ„κ³  λ§ˆμ§€λ§‰μ— λƒ₯이 μ§‘μ‚¬λ‹˜μ΄ μžμ—°μŠ€λŸ½κ²Œ κ±·λ‹€κ°€ λ©ˆμΆ”κ²Œ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
μ’€ 더 μ„ΈλΆ€μ μœΌλ‘œ 말씀을 λ“œλ¦¬μžλ©΄ 가속도가 뢙지 μ•Šκ²Œ ν•˜κΈ° μœ„ν•΄ animation: cat 3s linear;λ₯Ό μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ λ§ˆμ§€λ§‰μ— λƒ₯이 μ§‘μ‚¬λ‹˜μ„ λ©ˆμΆ”κ²Œ ν•˜κΈ° μœ„ν•΄ animation-fill-mode: forwards;속성을 λΆ€μ—¬ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
%λŠ” 10%둜 λ‚˜λˆˆ κ²ƒμ—μ„œ YμΆ• 값을 -20px둜 μ£Όμ—ˆμŠ΅λ‹ˆλ‹€.
<!DOCTYPE html> <html> <head> <style> body, img, div{ padding: 0; margin: 0; } @keyframes one { from{ background-position: 0px, 0px; } to { background-position: -3730px, 0; } } @keyframes two { from{ background-position: 0px, 0px; } to { background-position: -5346px, 0; } } @keyframes seven { from{ background-position: 0px, 0px; } to { background-position: -3300px, 0; } } @keyframes cat { 10% { transform: translateY(0) scale(0.3); background: url(./animation/cat/1.png) no-repeat; } 20% { transform: translateX(-20px) scale(0.3); background: url(./animation/cat/2.png) no-repeat; } 30% { transform: translateX(-40px) scale(0.3); background: url(./animation/cat/3.png) no-repeat; } 40% { transform: translateX(-60px) scale(0.3); background: url(./animation/cat/1.png) no-repeat; } 50% { transform: translateX(-80px) scale(0.3); background: url(./animation/cat/2.png) no-repeat; } 60% { transform: translateX(-100px) scale(0.3); background: url(./animation/cat/3.png) no-repeat; } 70% { transform: translateX(-120px) scale(0.3); background: url(./animation/cat/1.png) no-repeat; } 80% { transform: translateX(-140px) scale(0.3); background: url(./animation/cat/2.png) no-repeat; } 90% { transform: translateX(-160px) scale(0.3); background: url(./animation/cat/3.png) no-repeat; } 100% { transform: translateX(-180px) scale(0.3); background: url(./animation/cat/1.png) no-repeat; } } .building1{ width: 110px; height: 180px; background: url(./animation/building/building1.png) no-repeat; animation: one 5s steps(33); animation-fill-mode: forwards; transform: scale(0.5); position: absolute; top: 10px; left: 10px; } .building2{ width: 165px; height: 180px; background: url(./animation/building/building2.png) no-repeat; animation: two 5s steps(32); animation-fill-mode: forwards; transform: scale(0.5); position: absolute; top: 300px; left: 300px; } .building7{ width: 150px; height: 180px; background: url(./animation/building/building7.png) no-repeat; animation: seven 5s steps(22); animation-fill-mode: forwards; position: absolute; top: 170px; left: 150px; } .cat{ width: 313px; height: 436px; background: url(./animation/cat.png) no-repeat; animation: cat 3s linear; animation-fill-mode: forwards; transform: scale(0.3); position: absolute; top: 10px; left: 600px; } .back{ width: 100vw; height: 150vh; background-color: YellowGreen; position: relative; } </style> </head> <body> <div class="back"> <div class="cat"></div> <div class="building1"></div> <div class="building2"></div> <div class="building7"></div> </div> </body> </html>

2.5 μ—¬λŸ¬λΆ„μ„ μœ„ν•œ 과제

πŸ’‘
이미지λ₯Ό ν™œμš©ν•˜μ—¬ μ’€ 더 λ‹€μ–‘ν•œ μŠ€ν† λ¦¬ μ• λ‹ˆλ©”μ΄μ…˜μ„ λ§Œλ“€μ–΄λ³΄μ„Έμš”. μΉœκ΅¬λ“€λ„(μ–‘, μ—¬μš°, 토끼) λ§Œλ‚˜κ²Œ ν•˜μ‹œκ³ , λ‚˜λ¬΄λ„ λ°°μΉ˜ν•˜λ©°, 보닀 λ§Žμ€ 건물듀도 λ°°μΉ˜ν•΄λ³΄μ‹­μ‹œμ˜€.
λ’€νŽΈμ— JSκΉŒμ§€ κ³΅λΆ€ν•˜μ‹œκ³  λ‹€μ‹œ 이 μ±•ν„°λ‘œ λŒμ•„μ™€ κ³΅λΆ€ν•΄λ³΄μ‹œλ©΄ μ’€ 더 λ§Žμ€ 도움이 λ˜μ‹€ κ²ƒμž…λ‹ˆλ‹€.
Β