안녕하세요! 프론트엔드 개발의 세계에 오신 것을 환영합니다. 오늘 저와 함께 살펴볼 내용은 웹 페이지에 생동감을 불어넣어 줄 CSS 애니메이션입니다.
CSS 애니메이션을 사용하면 CSS 스타일이 하나의 설정(상태)에서 다른 설정으로 부드럽게 전환되는 멋진 애니메이션을 만들 수 있어요. 애니메이션은 크게 두 가지 요소로 이루어집니다. 첫 번째는 애니메이션의 설정을 지정하는 'CSS 스타일'이고, 두 번째는 애니메이션의 시작과 끝 상태, 그리고 중간중간 어떻게 변해야 하는지(경유지)를 알려주는 '키프레임(keyframes) 세트'입니다.
기존에 JavaScript로 애니메이션을 구현하던 방식에 비해, CSS 애니메이션은 다음과 같은 세 가지 아주 강력한 장점이 있습니다:
💡 강사님의 꿀팁: 실무에서도 복잡한 로직이 필요한 게 아니라면, UI의 시각적인 전환 효과는 대부분 CSS 애니메이션으로 처리하는 것이 성능 면에서 훨씬 유리합니다! JavaScript는 데이터를 다루거나 복잡한 상태를 제어하는 데 양보하고, 시각적인 요소는 CSS에 맡겨주세요.
CSS 애니메이션 시퀀스를 만들려면, 애니메이션을 적용하고 싶은 요소에 animation 속성이나 그 하위 속성(sub-properties)들을 적용해야 합니다. 이 속성들을 통해 애니메이션이 진행되는 타이밍, 지속 시간, 그리고 여러 진행 방식에 대한 세부 사항들을 세팅할 수 있어요.
단, 여기서 주의할 점은 이 속성들이 애니메이션의 실제 시각적인 모습(어떤 색으로 변할지, 얼마나 이동할지 등)을 설정하는 것은 아니라는 점입니다. 실제 외형의 변화는 아래 키프레임을 사용하여 애니메이션 시퀀스 정의하기 섹션에서 배울 @keyframes 앳룰(@-rule)을 통해 작성한답니다.
animation 속성의 하위 속성들은 다음과 같습니다:
animation-compositionanimation 단축 속성에 포함되지 않습니다.)animation-delayanimation-directionanimation-durationanimation-fill-mode참고: 애니메이션을 forwards 모드로 채우게 되면, 애니메이션 된 속성들은 마치
will-change속성에 값이 포함된 것처럼 동작합니다. 만약 애니메이션 중에 새로운 쌓임 문맥(stacking context)이 만들어졌다면, 대상 요소는 애니메이션이 완전히 끝난 후에도 그 쌓임 문맥을 계속 유지하게 됩니다.
animation-iteration-countanimation-name@keyframes 앳룰의 이름을 지정합니다.animation-play-stateanimation-timelineanimation-timing-function💡 강사님의 꿀팁: 현업에서 특히
animation-fill-mode: forwards는 무조건 외워두셔야 합니다! 팝업창이 서서히 나타나는 애니메이션을 만들었는데 끝나고 나서 다시 팝업이 휙! 사라져 버린다면, 대부분 이 속성을forwards로 주지 않아서 그래요. 끝난 상태를 그대로 유지하라는 뜻이랍니다. 그리고 타이밍 함수(timing-function)를 잘 활용하면 정말 생동감 넘치는 찰진 움직임을 만들 수 있어요!
애니메이션의 타이밍과 진행 방식을 다 설정했다면, 이제 애니메이션의 뼈대이자 외형을 정의해야 합니다. 이는 @keyframes 앳룰을 사용해서 하나 이상의 '키프레임(keyframe)'을 만들어주면 된답니다. 각각의 키프레임은 애니메이션이 진행되는 과정 중 특정 시점에 요소가 어떻게 렌더링 되어야 하는지를 설명해 줍니다.
애니메이션의 전체 소요 시간은 위에서 설명한 CSS 스타일(animation-duration 등)에서 이미 지정했기 때문에, 키프레임 내부에서는 <percentage>(퍼센트)를 사용해서 애니메이션 전체 시퀀스 중 어느 시점인지를 나타냅니다.
0%는 애니메이션 시퀀스의 맨 처음 시작 순간을 나타냅니다.100%는 애니메이션의 맨 마지막 최종 상태를 나타냅니다. 이 두 시점은 너무나도 중요하기 때문에 특별한 별칭(alias)을 가지고 있어요. 바로 from(0%와 동일)과 to(100%와 동일)입니다. 이 두 값은 선택 사항(optional)이에요. 만약 from이나 0%, 또는 to나 100%를 따로 지정하지 않으면 브라우저는 해당 요소가 원래 가지고 있던 계산된 속성 값들을 시작점이나 끝점으로 알아서 설정해 줍니다.
물론 시작과 끝 사이의 중간 단계를 표현하고 싶다면 0%부터 100% 사이의 퍼센트 값을 가진 추가 키프레임들을 원하는 만큼 얼마든지 넣으실 수 있어요.
💡 강사님의 꿀팁: 저는 개인적으로
from,to보다는0%,100%로 작성하는 습관을 들이시는 걸 추천해요. 처음엔 시작과 끝만 있다가도 나중에 기획이 바뀌어서50%지점에 튕기는 효과를 넣어달라고 할 수도 있거든요! 숫자로 통일해두면 유지보수하기 훨씬 편해집니다.
animation 단축 속성(shorthand)을 사용하면 코드를 길게 나열할 필요 없이 아주 깔끔하게 줄일 수 있어서 유용합니다. 예를 들어, 이 글을 읽으며 배운 여러 속성들을 이렇게 길게 쓸 수 있죠:
p {
animation-duration: 3s;
animation-name: slide-in;
animation-iteration-count: infinite;
animation-direction: alternate;
}
이 코드는 animation 단축 속성을 써서 아래처럼 딱 한 줄로 줄일 수 있습니다!
p {
animation: 3s infinite alternate slide-in;
}
이 단축 속성을 사용할 때 각 애니메이션 속성 값들을 어떤 순서로 적어야 하는지 자세히 알고 싶으시다면 animation 레퍼런스 페이지를 확인해 보세요.
💡 강사님의 꿀팁: 단축 속성에서 정말 많은 분이 헷갈려 하는 부분이 바로 '시간'을 나타내는 값의 순서입니다. 예를 들어
animation: 2s 1s slide-in;처럼 시간이 두 번 나오면, 항상 첫 번째 시간 값이duration(재생 시간)이고, 두 번째 시간 값이delay(지연 시간)로 인식됩니다! 이것만 기억하셔도 큰 실수를 줄일 수 있어요.
CSS 애니메이션의 각 개별(longhand) 속성들은 쉼표(,)로 구분해서 여러 개의 값을 받을 수 있습니다. 이 기능은 하나의 요소에 하나의 CSS 규칙으로 여러 개의 애니메이션을 동시에 적용하고 싶을 때 사용해요. 각각의 애니메이션마다 지속 시간, 반복 횟수 등을 다 다르게 설정할 수 있거든요. 어떻게 매칭되는지 몇 가지 간단한 예시를 통해 설명해 드릴게요.
첫 번째 예시에서는 지속 시간(duration)이 3개, 반복 횟수(iteration-count)가 3개 주어졌습니다. 각각의 값은 animation-name에 나열된 순서와 동일한 위치의 값과 짝이 지어집니다.
따라서 fadeInOut 애니메이션은 2.5s의 시간과 2번의 반복 횟수를 가지고, bounce 애니메이션은 1s의 시간과 5번의 반복 횟수를 갖게 됩니다.
animation-name: fadeInOut, moveLeft300px, bounce;
animation-duration: 2.5s, 5s, 1s;
animation-iteration-count: 2, 1, 5;
두 번째 예시에서는 애니메이션 이름은 3개가 설정되었는데, 지속 시간과 반복 횟수는 딱 1개씩만 적혀 있네요. 이 경우에는 세 개의 애니메이션 모두가 동일하게 하나의 지속 시간(3s)과 반복 횟수(1)를 나눠 쓰게 됩니다.
animation-name: fadeInOut, moveLeft300px, bounce;
animation-duration: 3s;
animation-iteration-count: 1;
세 번째 예시를 볼까요? 애니메이션 이름은 3개인데, 지속 시간과 반복 횟수는 2개뿐입니다. 이렇게 리스트의 값 개수가 부족해서 각각의 애니메이션에 하나씩 매칭해 줄 수 없는 상황이 오면, 브라우저는 리스트의 첫 번째 값부터 마지막 값까지 순서대로 할당하다가 값이 끝나면 다시 첫 번째 값으로 돌아가서 재사용(cycle)합니다.
즉, fadeInOut은 첫 번째 값인 2.5s를 받고, moveLeft300px은 두 번째 값이자 마지막 값인 5s를 받습니다. 이제 지속 시간 값이 떨어졌죠? 그러면 다시 처음으로 돌아가서, 세 번째 애니메이션인 bounce는 다시 첫 번째 값인 2.5s를 받게 되는 식입니다. 반복 횟수 값이나 그 외 다른 속성 값들도 이와 똑같은 방식으로 할당됩니다.
animation-name: fadeInOut, moveLeft300px, bounce;
animation-duration: 2.5s, 5s;
animation-iteration-count: 2, 1;
만약 반대로 애니메이션 이름보다 값이 더 많다면 어떻게 될까요? 예를 들어 애니메이션 이름은 3개인데 animation-duration 값이 5개나 있다면, 남아도는 여분의 두 animation-duration 값은 어떤 애니메이션에도 적용되지 않고 그냥 무시됩니다.
이제부터 배운 내용을 바탕으로 여러 가지 예제를 직접 만들어볼까요?
가장 기본적인 이 예제는 translate와 scale 속성을 활용해서, <p> 요소의 텍스트가 브라우저 창 오른쪽 바깥에서 안쪽으로 스르륵 미끄러져 들어오게 만드는 스타일입니다.
Play (Run example in MDN Playground)
p {
animation-duration: 3s;
animation-name: slide-in;
}
@keyframes slide-in {
from {
translate: 150vw 0;
scale: 200% 1;
}
to {
translate: 0 0;
scale: 100% 1;
}
}
이 예제에서 <p> 요소의 스타일을 보면, animation-duration 속성을 사용해서 애니메이션이 시작부터 끝까지 총 3초(3s) 동안 실행되도록 지정했습니다. 그리고 이 애니메이션 시퀀스의 키프레임을 정의한 @keyframes 앳룰의 이름이 slide-in이라고 알려주고 있죠.
키프레임은 딱 두 개를 만들었습니다. 첫 번째 키프레임은 0% 지점(from 별칭 사용)입니다. 여기서 요소의 translate를 150vw로 설정했어요 (즉, 텍스트가 컨테이닝 블록의 오른쪽 경계를 훨씬 넘어간 화면 바깥에 위치합니다). 동시에 scale을 200%로 주어서 글자 폭이 기본보다 두 배로 넓어지게 만들었죠. 이렇게 하면 애니메이션의 첫 프레임에서 문단이 브라우저 창 오른쪽 바깥으로 벗어난 상태로 시작하게 됩니다.
두 번째 키프레임은 100% 지점(to 별칭 사용)입니다. translate는 0%로 돌아오고 요소의 scale도 기본 크기인 1(100%)로 돌아옵니다. 그 결과, 헤더 텍스트가 원래 있어야 할 제자리(콘텐츠 영역 왼쪽)에 예쁘게 안착하면서 애니메이션이 끝나게 됩니다.
Play (Run example in MDN Playground)
참고: 페이지를 새로고침하면 애니메이션이 실행되는 걸 확인하실 수 있습니다.
방금 만든 애니메이션에 키프레임을 하나 더 추가해 보겠습니다. 이번엔 문단 속 'Alice'라는 이름만 콕 집어서, 오른쪽에서 왼쪽으로 미끄러져 들어올 때 글씨 색이 분홍색으로 변하면서 커졌다가 원래 크기와 색상으로 돌아오게 만들고 싶어요.
이때 font-size를 변경해서 글씨를 키울 수도 있겠지만, 폰트 사이즈처럼 박스 모델(box model) 자체를 건드리는 속성들을 애니메이션 하면 성능이 심각하게 저하될 수 있어요(리플로우 발생). 그 대신 앨리스의 이름만 태그로 감싼 뒤, 해당 <span>에 따로 스케일(scale)과 색상을 부여하는 방식을 써보겠습니다. 이렇게 하려면 <span>에만 영향을 주는 두 번째 애니메이션을 만들어야겠죠?
Play (Run example in MDN Playground)
@keyframes grow-shrink {
25%,
75% {
scale: 100%;
}
50% {
scale: 200%;
color: magenta;
}
}
전체 코드는 이제 이렇게 됩니다:
Play (Run example in MDN Playground)
p {
animation-duration: 3s;
animation-name: slide-in;
}
p span {
display: inline-block;
animation-duration: 3s;
animation-name: grow-shrink;
}
@keyframes slide-in {
from {
translate: 150vw 0;
scale: 200% 1;
}
to {
translate: 0 0;
scale: 100% 1;
}
}
@keyframes grow-shrink {
25%,
75% {
scale: 100%;
}
50% {
scale: 200%;
color: magenta;
}
}
그리고 HTML에서는 "Alice" 양옆에 을 씌워줍니다:
Play (Run example in MDN Playground)
<p>
애벌레와 <span>Alice</span>는 한동안 말없이 서로를 쳐다보았습니다: 마침내 애벌레가 입에서
물담배를 빼고는 나른하고 졸린 목소리로 그녀에게 말을 걸었습니다.
</p>
이 코드는 브라우저에게 "처음 25%와 마지막 25%(75%~100%) 동안에는 이름이 정상 크기(100%)로 보이다가, 중간 지점인 50%일 때는 크기가 커지고(200%) 색깔도 마젠타(magenta)로 변하게 해 줘!"라고 명령하는 것입니다. 참고로 span 태그의 display 속성을 inline-block으로 바꾼 걸 볼 수 있는데, 이건 매우 중요한 포인트예요! transform 계열의 속성(scale, translate 등)들은 inline 요소(비치환 인라인 요소)에는 먹히지 않기 때문에 꼭 바꿔주어야 합니다.
참고: 페이지를 새로고침하면 애니메이션이 어떻게 변했는지 확인하실 수 있습니다.
한 번 끝나고 마는 게 아쉬운가요? 애니메이션을 계속해서 스스로 반복하게 만들려면, animation-iteration-count 속성에 반복할 횟수를 지정하면 됩니다. 끝없이 영원히 움직이게 하고 싶다면 infinite 값을 쿨하게 넣어주세요!
Play (Run example in MDN Playground)
p {
animation-duration: 3s;
animation-name: slide-in;
animation-iteration-count: infinite;
}
이제 애니메이션이 무한 반복되긴 하는데, 매번 시작할 때마다 글자가 오른쪽 끝으로 휙! 점프해서 다시 나타나니까 좀 부자연스럽죠? 화면의 양쪽을 탁구공처럼 자연스럽게 왔다 갔다(back and forth)하게 만들고 싶으실 거예요. 아주 간단합니다! animation-direction을 alternate로 설정해 주면 끝이에요.
Play (Run example in MDN Playground)
p {
animation-duration: 3s;
animation-name: slide-in;
animation-iteration-count: infinite;
animation-direction: alternate;
}
애니메이션이 시작되고, 중간에 반복되고, 끝나는 각각의 시점을 우리가 포착할 수 있다면 어떨까요? JavaScript의 애니메이션 이벤트(animation events)를 활용하면 애니메이션에 대한 추가적인 제어 권한과 유용한 정보들을 얻을 수 있습니다.
AnimationEvent 객체로 대표되는 이 이벤트들은 언제 애니메이션이 시작(start)하고, 끝(finish)나고, 새 사이클을 시작(begin a new iteration)하는지 정확히 감지해 냅니다. 게다가 각 이벤트 객체 안에는 이벤트가 발생한 정확한 시간(time)과 이벤트를 발생시킨 애니메이션의 이름(name) 정보까지 꾹꾹 담겨 있어요.
이 이벤트들이 실제로 어떻게 동작하는지 엿보기 위해서, 아까 만든 텍스트 슬라이드 예제에 JavaScript를 얹어 애니메이션 이벤트 정보들을 화면에 출력해 보겠습니다.
CSS에는 앞서 만든 것과 동일한 키프레임 애니메이션을 준비합니다. 이 애니메이션("slide-in")은 3초 동안 진행되고, 총 3번 반복하며, 매번 번갈아 가면서(alternate) 방향을 바꿀 거예요.
Play (Run example in MDN Playground)
.slide-in {
animation-duration: 3s;
animation-name: slide-in;
animation-iteration-count: 3;
animation-direction: alternate;
}
JavaScript 코드를 통해 애니메이션과 관련된 세 가지 이벤트(animationstart, animationend, animationiteration)를 모두 귀 기울여 듣게(listen) 만들 겁니다. 문서가 처음 로드될 때 이 코드를 호출해서 세팅을 마칩니다.
Play (Run example in MDN Playground)
const element = document.getElementById("watch-me");
element.addEventListener("animationstart", listener);
element.addEventListener("animationend", listener);
element.addEventListener("animationiteration", listener);
element.className = "slide-in";
코드가 아주 기본적이죠? 이벤트 등록에 대한 자세한 내용은 eventTarget.addEventListener() 문서를 참고하시면 됩니다. 이 코드의 마지막 줄을 보시면, 이벤트 리스너를 다 등록한 후에야 요소의 class를 "slide-in"으로 바꿔주고 있어요. 바로 이 순간이 애니메이션이 실제로 시작되도록 방아쇠를 당기는(start) 시점입니다.
왜 이렇게 했을까요? 만약 HTML에 처음부터 클래스를 달아두었다면, 우리 JavaScript 코드가 실행되기도 전에 이미 브라우저가 애니메이션을 시작해 버려서 animationstart 이벤트를 영영 놓치고 말았을 테니까요! 그래서 리스너를 먼저 쫙 깔아두고 우리가 원하는 타이밍에 클래스를 추가해 준 것입니다.
이벤트가 발생하면 아까 등록해 둔 listener() 함수로 이벤트 정보가 쏙 전달됩니다. 코드는 아래와 같습니다.
Play (Run example in MDN Playground)
function listener(event) {
const l = document.createElement("li");
switch (event.type) {
case "animationstart":
l.textContent = `Started: elapsed time is ${event.elapsedTime}`;
break;
case "animationend":
l.textContent = `Ended: elapsed time is ${event.elapsedTime}`;
break;
case "animationiteration":
l.textContent = `New loop started at time ${event.elapsedTime}`;
break;
}
document.getElementById("output").appendChild(l);
}
이 코드도 아주 명확하죠. 건네받은 event.type을 살펴보고 "시작했네? 끝났네? 반복하네?"를 파악한 다음, 로그를 보여줄 <ul>(순서 없는 목록)에 메시지가 담긴 리스트 아이템을 착착 붙여주는 역할입니다.
결과적으로 출력을 보면 대략 이런 모습일 거예요:
시간(time)을 잘 보시면, 우리가 CSS에서 딱 3초(3s)로 설정해 두었지만 실제로는 소수점 아래로 미세하게 오차가 있는 걸 알 수 있습니다. 이는 시스템 성능에 따라 약간의 차이가 생길 수 있다는 의미예요. 그리고 또 한 가지! 3번째 반복을 모두 마치고 애니메이션이 끝날 때는 animationiteration 이벤트 대신 animationend 이벤트가 딱 한 번 발생하며 대장정을 마무리합니다.
완성을 위해 텍스트 로그를 출력할 <ul> 리스트가 포함된 HTML 마크업도 보여드릴게요:
Play (Run example in MDN Playground)
<h1 id="watch-me">Watch me move</h1>
<p>
이 예제는 CSS 애니메이션을 사용하여 <code>H1</code> 요소가 페이지를
가로질러 이동하게 만드는 방법을 보여줍니다.
</p>
<p>
게다가 애니메이션 이벤트가 실행될 때마다 텍스트가 출력되므로
이벤트가 언제 일어나는지 눈으로 직접 볼 수 있죠.
</p>
<ul id="output"></ul>
참고: 페이지를 새로고침하면 애니메이션을 볼 수 있습니다.
마지막 팁입니다! 이 예제는 display 속성과 content-visibility 속성도 애니메이션으로 처리할 수 있다는 걸 보여줍니다. "어? display: none은 애니메이션이 안 먹히는 거 아니었나요?" 하셨을 텐데, 요즘 브라우저들은 꽤 발전했거든요! 요소를 DOM에서 숨길 때(display: none), 바로 뚝 끊어지며 사라지는 게 아니라 opacity(투명도)를 이용해서 스르륵 부드럽게 페이드 아웃(fade out) 되도록 만드는 진입/퇴장(entry/exit) 애니메이션에 아주 유용하게 쓰입니다.
이 기능을 지원하는 브라우저들은 display와 content-visibility를 불연속 애니메이션(discrete animation type)의 변형된 방식으로 처리합니다. 불연속 애니메이션이란, 0에서 1로 스르륵 변하는 게 아니라, 애니메이션 진행률 딱 50% 지점에서 값이 A에서 B로 휙! 하고 뒤집히는(flip) 걸 말해요.
하지만, 예외가 하나 있습니다. 바로 display: none이나 content-visibility: hidden 상태에서 눈에 보이는(visible) 상태로 애니메이션 할 때, 혹은 그 반대의 경우예요. 이때 브라우저는 애니메이션 지속 시간 내내 텍스트나 요소가 화면에 '보이도록' 알아서 값을 영리하게 뒤집어줍니다.
구체적으로 예를 들어 볼게요:
display를 none에서 block(또는 눈에 보이는 값)으로 애니메이션 할 때는, 애니메이션 지속 시간의 0%(시작 즉시) 지점에 값이 block으로 휙 바뀝니다. 그래서 애니메이션이 진행되는 내내 내용이 눈에 보입니다.display를 block에서 none으로 숨길 때는, 애니메이션 지속 시간의 마지막인 100%(끝날 때) 지점에 값이 none으로 바뀝니다. 덕분에 서서히 투명해지면서 페이드 아웃 되는 시간 내내 내용이 화면에 잘 보일 수 있는 것이죠.HTML에는 두 개의 <p> 태그가 있고 그 사이에 우리가 display: none에서 block으로 애니메이션 할 <div>가 숨어있습니다.
Play (Run example in MDN Playground)
<p>
화면 아무 곳이나 클릭하거나 아무 키나 눌러서 <code><div></code>를 숨김(hidden)과 표시(showing) 상태로 전환해보세요.
</p>
<div>
이 <code><div></code> 요소는 <code>display: none; opacity: 0</code>과
<code>display: block; opacity: 1</code> 사이를 자연스럽게 애니메이션합니다. 참 깔끔하죠?
</div>
<p>
위의 <code><div></code> 요소에 <code>display: none;</code>이 제대로
적용되었다가 지워지는지 보여주기 위한 단락입니다. 만약 <code>opacity</code>만
바꾸었다면, 안 보일 때도 DOM 상에 텅 빈 공간을 차지하고 있었을 테니까요!
</p>
Play (Run example in MDN Playground)
html {
height: 100vh;
}
div {
font-size: 1.6rem;
padding: 20px;
border: 3px solid red;
border-radius: 20px;
width: 480px;
opacity: 0;
display: none;
}
/* Animation classes */
div.fade-in {
display: block;
animation: fade-in 0.7s ease-in forwards;
}
div.fade-out {
animation: fade-out 0.7s ease-out forwards;
}
/* Animation keyframes */
@keyframes fade-in {
0% {
opacity: 0;
display: none;
}
100% {
opacity: 1;
display: block;
}
}
@keyframes fade-out {
0% {
opacity: 1;
display: block;
}
100% {
opacity: 0;
display: none;
}
}
가장 핵심은 키프레임 애니메이션 안에 display 속성을 함께 넣어준 것입니다! 옛날 같았으면 상상도 못 했을 방식이죠.
마지막으로, 애니메이션을 제어할 이벤트 리스너를 달아주는 작은 JavaScript 코드를 추가합니다. 사용자가 화면을 클릭하거나 키보드를 누르면, <div>가 나타나길 원할 땐 fade-in 클래스를 붙여주고, 사라지게 하고 싶을 땐 fade-out 클래스로 바꿔치기하는 식입니다.
Play (Run example in MDN Playground)
const divElem = document.querySelector("div");
const htmlElem = document.querySelector(":root");
htmlElem.addEventListener("click", showHide);
document.addEventListener("keydown", showHide);
function showHide() {
if (divElem.classList[0] === "fade-in") {
divElem.classList.remove("fade-in");
divElem.classList.add("fade-out");
} else {
divElem.classList.remove("fade-out");
divElem.classList.add("fade-in");
}
}
이 코드가 완성되면 화면에서 클릭할 때마다 뚝 끊기지 않고 부드럽게 요소가 나타났다가, 다시 서서히 투명해지며 완전히 DOM 영역에서 사라지는 우아한 트랜지션을 볼 수 있습니다.
더 깊이 파고들고 싶은 개발자분들은 아래 문서들을 곁들여 읽어보세요:
AnimationEvent이 문서가 학습에 도움이 되셨나요? (Was this page helpful to you?)
[Yes][No]
문서 기여 방법 알아보기: Learn how to contribute
최종 수정일: 2025년 12월 15일 (MDN contributors 작성)
이 문서를 GitHub에서 보기 | 문서의 문제점 신고하기