Transitions/Using transitions

김동현·2026년 3월 21일

mdn 학습 번역 - CSS

목록 보기
163/190

안녕하세요! 프론트엔드 개발자 취업을 위해 오늘도 열심히 달리고 계시는군요! 웹 프로필이나 독후감 사이트 같은 멋진 포트폴리오를 만들 때, UI 요소들이 딱딱하게 끊기며 변하는 것보다 스르륵 부드럽게 움직이면 훨씬 완성도 높은 웹사이트처럼 보이겠죠?

이번에 가져오신 문서는 바로 그런 '부드러운 전환'을 담당하는 'CSS 트랜지션(CSS transitions)'의 핵심 가이드입니다. React나 Next.js 환경에서 컴포넌트 단위로 개발할 때, 상태 변화에 따른 부드러운 애니메이션을 주기 위해 반드시 알아야 하는 필수 지식이기도 합니다. 면접에서도 자주 등장하는 개념이니, 공식 문서의 내용을 하나도 빠짐없이 제 실무 팁과 함께 구어체로 알기 쉽게 설명해 드릴게요!


CSS 트랜지션 사용하기 (Using CSS transitions)

CSS 트랜지션(CSS transitions)은 CSS 속성이 변경될 때 애니메이션 속도를 제어할 수 있는 방법을 제공합니다. 속성 변경 사항이 즉시 적용되게 하는 대신, 일정 시간(period of time)에 걸쳐 속성 변화가 일어나도록 만들 수 있습니다. 예를 들어, 어떤 요소의 색상을 흰색에서 검은색으로 변경하면 보통은 그 변화가 즉각적으로 일어납니다. 하지만 CSS 트랜지션을 활성화하면, 가속도 곡선(acceleration curve)을 따르는 시간 간격에 맞춰 변화가 일어납니다. 물론 이 모든 과정은 여러분의 마음대로 커스터마이징할 수 있습니다.

두 가지 상태 사이를 전환하는 애니메이션은 종종 암시적 트랜지션(implicit transitions)이라고 불립니다. 왜냐하면 시작 상태와 최종 상태 사이의 중간 상태들을 브라우저가 암시적으로 알아서 정의하고 그려주기 때문입니다.

A CSS transition tells the browser to draw the intermediate states between the initial and final states, showing the user a smooth transitions.

CSS 트랜지션을 사용하면 어떤 속성들을 애니메이션 할 것인지(명시적으로 나열하여), 애니메이션이 언제 시작될 것인지(지연 시간(delay) 설정), 트랜지션이 얼마나 오래 지속될 것인지(지속 시간(duration) 설정), 그리고 트랜지션이 어떤 방식으로 실행될 것인지(타이밍 함수(easing function) 정의, 예: 일정한 속도로 진행할지, 혹은 처음엔 빠르고 끝엔 느리게 진행할지 등)를 직접 결정할 수 있습니다.


이 문서의 목차 (In this article)


어떤 CSS 속성들을 트랜지션할 수 있나요? (Which CSS properties can be transitioned?)

웹 제작자는 어떤 속성을 어떤 방식으로 애니메이션 할지 직접 정의할 수 있습니다. 이를 통해 아주 복잡한 트랜지션을 만들어낼 수 있죠. 하지만 일부 속성들은 애니메이션을 적용하는 것 자체가 의미가 없기 때문에 애니메이션을 적용할 수 없습니다(not animatable).

참고 (Note):
auto 값은 꽤 복잡한 케이스입니다. CSS 명세에서는 auto 값에서 시작하거나 auto 값으로 끝나는 애니메이션을 권장하지 않습니다. Gecko 기반 브라우저 같은 일부 사용자 에이전트(브라우저)는 이 요구사항을 엄격하게 구현하지만, WebKit 기반 브라우저 같은 곳들은 덜 엄격합니다. 따라서 auto 값에 애니메이션을 사용하는 것은 브라우저와 그 버전에 따라 예측 불가능한 결과를 초래할 수 있으므로 피하는 것이 좋습니다.

💡 강사의 실무 팁 1: height: auto 애니메이션의 비밀
"아코디언 메뉴나 드롭다운 메뉴를 만들 때, 닫혀있을 땐 height: 0 이었다가 열리면 안의 내용물만큼 쫙 펼쳐지게 height: auto 로 부드럽게 트랜지션을 주고 싶어요!"
프론트엔드 개발을 하다 보면 100% 마주치게 되는 고민입니다. 하지만 공식 문서의 경고처럼 CSS는 0에서 auto로 넘어가는 중간값을 계산하지 못합니다! 실무에서는 이를 해결하기 위해 max-height를 아주 큰 값으로 설정해서 애니메이션 하거나, CSS Grid의 1fr을 활용하거나, 또는 자바스크립트로 요소의 scrollHeight를 직접 계산해서 px 값으로 넣어주는 트릭을 사용합니다. 기술 면접에서도 종종 물어보는 주제니 꼭 기억해 두세요!


트랜지션 정의하기 (Defining transitions)

CSS 트랜지션은 단축 속성인 transition을 사용하여 제어합니다. 이 방법은 트랜지션을 구성하는 가장 좋은 방법입니다. 파라미터들의 싱크가 어긋나는 것을 방지해 주어, CSS 디버깅에 많은 시간을 낭비하는 답답한 상황을 줄여주기 때문입니다.

트랜지션을 구성하는 개별 요소들은 다음의 하위 속성들을 통해 제어할 수 있습니다:

  • transition-property
    • 트랜지션을 적용할 CSS 속성의 이름(들)을 지정합니다. 여기에 나열된 속성들만 트랜지션 되는 동안 애니메이션 효과가 적용되며, 그 외의 다른 모든 속성들의 변경은 평소처럼 즉각적으로(순간적으로) 일어납니다.
  • transition-duration
    • 트랜지션이 완료되는 데 걸리는 시간을 지정합니다. 하나의 지속 시간만 지정하여 트랜지션 되는 모든 속성에 동일하게 적용할 수도 있고, 여러 개의 값을 지정하여 각각의 속성이 서로 다른 시간 동안 전환되도록 만들 수도 있습니다.
  • transition-timing-function
    • 속성의 중간값들이 어떻게 계산될지를 정의하는 함수를 지정합니다. 타이밍 함수(Easing functions)는 트랜지션의 중간값들이 도출되는 방식을 결정합니다. 대부분의 타이밍 함수는 3차 베지어 곡선(cubic bezier)을 정의하는 네 개의 점으로 이루어진 그래프를 제공하여 지정할 수 있습니다. 타이밍 함수 치트 시트 (Easing functions cheat sheet)에서 마음에 드는 이징(easing) 값을 골라 사용할 수도 있습니다.
  • transition-delay
    • 속성이 변경된 시점부터 트랜지션이 실제로 시작될 때까지 기다릴 시간(대기 시간)을 정의합니다.

transition 단축 속성 문법은 다음과 같이 작성합니다:

transition: <property> <duration> <timing-function> <delay>;

예제 (Examples)

기본 예제 (Basic example)

이 예제는 사용자가 요소 위에 마우스를 올린(hover) 후 2초의 지연 시간을 거친 뒤, 4초 동안 글꼴 크기(font size)가 변경되는 트랜지션을 수행합니다:

#delay {
  font-size: 14px;
  transition-property: font-size;
  transition-duration: 4s;
  transition-delay: 2s;
}

#delay:hover {
  font-size: 36px;
}

여러 속성을 애니메이션 하는 예제 (Multiple animated properties example)

<body>
  <p>
    아래 박스는 width, height, background-color, rotate에 대한 트랜지션을 결합한 것입니다. 박스 위에 마우스를 올려 애니메이션이 어떻게 작동하는지 확인해 보세요.
  </p>
  <div class="box">Sample</div>
</body>

CSS

.box {
  border-style: solid;
  border-width: 1px;
  display: block;
  width: 100px;
  height: 100px;
  background-color: blue;
  transition:
    width 2s,
    height 2s,
    background-color 2s,
    rotate 2s;
}

.box:hover {
  background-color: #ffcccc;
  width: 200px;
  height: 200px;
  rotate: 180deg;
}

속성 값 목록의 길이가 서로 다를 때 (When property value lists are of different lengths)

만약 어떤 하위 속성의 값 목록이 다른 것들보다 짧다면, 개수를 맞추기 위해 그 값들이 반복(repeated)됩니다. 예를 들면 다음과 같습니다:

div {
  transition-property: opacity, left, top, height;
  transition-duration: 3s, 5s;
}

위 코드는 내부적으로 아래와 같이 처리됩니다:

div {
  transition-property: opacity, left, top, height;
  transition-duration: 3s, 5s, 3s, 5s; /* 3s, 5s가 부족한 개수만큼 반복되었습니다! */
}

마찬가지로, 다른 속성의 값 목록이 transition-property에 나열된 속성 개수보다 더 길다면, 초과한 값들은 무시되고 잘려나갑니다(truncated). 다음 CSS를 살펴보세요:

div {
  transition-property: opacity, left;
  transition-duration: 3s, 5s, 2s, 1s;
}

이 코드는 다음과 같이 해석됩니다:

div {
  transition-property: opacity, left;
  transition-duration: 3s, 5s; /* 속성이 두 개뿐이므로 뒤에 적힌 2s, 1s는 무시됩니다. */
}

메뉴를 하이라이트 할 때 트랜지션 사용하기 (Using transitions when highlighting menus)

CSS의 아주 흔한 사용 사례 중 하나는 사용자가 마우스 커서를 메뉴 아이템 위에 올렸을 때(hover) 해당 항목을 강조 표시(highlight)하는 것입니다. 트랜지션을 사용하면 이 효과를 훨씬 더 매력적으로 만들기 쉽습니다.

먼저 HTML로 메뉴를 구성해 보겠습니다:

<nav>
  <a href="#">Home</a>
  <a href="#">About</a>
  <a href="#">Contact Us</a>
  <a href="#">Links</a>
</nav>

그런 다음 메뉴의 디자인(look and feel)을 구현하기 위한 CSS를 작성합니다:

nav {
  display: flex;
  gap: 0.5rem;
}

a {
  flex: 1;
  background-color: #333333;
  color: white;
  border: 1px solid;
  padding: 0.5rem;
  text-align: center;
  text-decoration: none;
  transition: all 0.5s ease-out; /* 배경색, 글자색이 변할 때 0.5초 동안 서서히 변하도록 설정합니다 */
}

a:hover,
a:focus {
  background-color: white;
  color: #333333;
}

이 CSS는 메뉴의 외관을 설정하며, 요소가 :hover 상태이거나 :focus 상태가 되었을 때 배경색과 텍스트 색상이 모두 변경되도록 만들어 줍니다.


displaycontent-visibility 트랜지션하기 (Transitioning display and content-visibility)

이 예제는 display 속성과 content-visibility 속성에 어떻게 트랜지션을 적용할 수 있는지 보여줍니다. 이 동작은 예를 들어 DOM에서 display: none으로 컨테이너를 아예 제거하고 싶지만, 뚝딱 사라지게 냅두지 않고 opacity를 통해 서서히 페이드아웃(fade out) 되며 사라지게 하는 진입/퇴장(entry/exit) 애니메이션을 만들 때 매우 유용합니다.

💡 강사의 실무 팁 2: 이거 진짜 최신 CSS의 혁명입니다!
예전에는 모달(Modal) 창을 닫을 때 부드럽게 사라지게 하려면 자바스크립트의 setTimeout을 써서 투명도 애니메이션이 끝날 때까지 기다렸다가 display: none을 먹이거나, framer-motion 같은 무거운 라이브러리를 써야 했어요. 하지만 이제 최신 CSS 문법을 활용하면 오직 CSS만으로 모달 창의 페이드아웃 효과를 완벽하게 구현할 수 있습니다!

최신 브라우저들은 displaycontent-visibility불연속 애니메이션 유형 (discrete animation type)의 한 변형으로 취급하여 트랜지션을 지원합니다. 일반적으로 불연속 애니메이션이란, 애니메이션 시간이 50% 진행되었을 때 두 값 사이를 휙 하고 전환(flip)하는 것을 뜻합니다.

하지만 예외가 있습니다. 바로 display: none이나 content-visibility: hidden 상태로(또는 그 상태로부터) 애니메이션을 할 때입니다. 이 경우 브라우저는 전환되는 콘텐츠가 애니메이션 지속 시간 내내 화면에 보이도록(보장하기 위해) 값의 전환 시점을 조정합니다.

예를 들면 다음과 같습니다:

  • display 값을 none에서 block(또는 다른 보이게 하는 값)으로 전환할 때: 애니메이션 진행률 0% 시점에 값이 즉시 block으로 전환되어, 애니메이션 내내 요소가 화면에 보이게 됩니다.
  • display 값을 block에서 none으로 전환할 때: 애니메이션 진행률 100% 시점(맨 마지막)에 값이 none으로 전환되어, 투명해지는 애니메이션이 진행되는 내내 요소가 화면에 보이도록 유지해 줍니다.

이 속성들에 트랜지션을 적용하려면, 반드시 트랜지션 설정에 transition-behavior: allow-discrete 속성을 추가해야 합니다. 이 설정이 있어야만 displaycontent-visibility의 트랜지션이 활성화됩니다.

또한 display에 트랜지션을 적용할 때는, 요소가 DOM에 처음 나타날 때(예를 들어 displaynone에서 다른 상태로 변경되며 첫 스타일 업데이트를 받을 때) 시작할 기준점을 제공하기 위해 반드시 @starting-style 블록이 필요합니다. 이는 예기치 않은 동작을 방지하기 위함입니다. 기본적으로 CSS 트랜지션은 요소가 DOM에 처음 나타나는 그 첫 번째 스타일 업데이트 시점에는 트리거되지 않기 때문입니다.
반면 content-visibility 애니메이션은 @starting-style 블록에 시작값을 지정할 필요가 없습니다. content-visibilitydisplay처럼 DOM에서 요소를 아예 렌더링 파이프라인에서 숨기는 것이 아니라, 그저 콘텐츠 부분의 렌더링만 건너뛰기(skip) 때문입니다.

HTML

이 HTML에는 두 개의 <p> 요소 사이에 display: none에서 block으로 애니메이션 될 <div>가 하나 들어있습니다.

<p>
  화면 아무 곳이나 클릭하거나 아무 키나 눌러서 아래 <code>&lt;div&gt;</code>의 숨김/표시 상태를 전환해 보세요.
</p>

<div><code>&lt;div&gt;</code> 요소는
  <code>display: none; opacity: 0</code> 상태와
  <code>display: block; opacity: 1</code> 상태 사이를 부드럽게 전환(transition)합니다. 멋지죠?
</div>

<p>
  이건 아래쪽 단락입니다. 위쪽 <code>&lt;div&gt;</code> 요소에 실제로 <code>display: none;</code>이 적용되었다가 해제되는 것을 보여주기 위한 단락입니다. 만약 투명도(<code>opacity</code>)만 조절되었다면, <code>div</code>가 투명할 때도 이 단락 위쪽에 항상 빈 공간(자리)을 차지하고 있었을 것입니다.
</p>

CSS

html {
  height: 100vh;
}

div {
  font-size: 1.6rem;
  padding: 20px;
  border: 3px solid red;
  border-radius: 20px;
  width: 480px;

  display: none; /* 기본 상태는 숨김 */
  opacity: 0;
  transition:
    opacity 1s,
    display 1s allow-discrete;
  /* 다음과 같이 단축해서 쓸 수도 있습니다:
  transition: all 1s allow-discrete; */
}

.showing {
  opacity: 1;
  display: block; /* 클래스가 붙으면 보여줍니다 */
}

/* display가 none에서 block으로 바뀔 때 투명도가 0에서 시작하도록 명시합니다 */
@starting-style {
  .showing {
    opacity: 0;
  }
}

@starting-style 블록이 트랜지션의 '시작 스타일'을 지정하는 데 사용된 점, 그리고 트랜지션 목록에 display 속성이 포함되어 있으며 그 옆에 allow-discrete 키워드가 함께 설정된 점에 주목하세요!

JavaScript

마지막으로, 사용자의 클릭이나 키보드 입력에 맞춰 showing 클래스를 토글(toggle)하여 트랜지션을 유발하는 간단한 자바스크립트를 추가합니다.

const divElem = document.querySelector("div");
const htmlElem = document.querySelector(":root");

htmlElem.addEventListener("click", showHide);
document.addEventListener("keydown", showHide);

function showHide() {
  divElem.classList.toggle("showing");
}

자바스크립트 예제 (JavaScript examples)

참고 (Note):
다음 상황 직후에 트랜지션을 사용하려고 할 때는 주의가 필요합니다:

  • 자바스크립트의 .appendChild()를 사용해 DOM에 방금 막 요소를 추가했을 때
  • 요소의 display: none; 속성을 막 제거했을 때

이런 상황에서는 브라우저가 "요소가 초기 상태를 거친 적이 없고, 태어날 때부터 최종 상태였다"고 취급해 버려서 애니메이션이 스킵될 수 있습니다. 이 한계를 극복하는 고전적인 방법 중 하나는, 트랜지션을 주고 싶은 CSS 속성을 변경하기 직전에 setTimeout()을 사용해 몇 밀리초(milliseconds) 정도 아주 약간의 시차를 두는 것입니다.

자바스크립트 기능을 부드럽게 만들기 위해 트랜지션 사용하기 (Using transitions to make JavaScript functionality smooth)

자바스크립트 코드(로직) 자체를 수정하지 않고도 동작을 훨씬 부드럽게 보이도록 만들고 싶을 때 트랜지션은 아주 훌륭한 도구가 됩니다. 다음 예제를 살펴보세요.

<p>공을 움직이려면 아무 곳이나 클릭하세요</p>
<div id="foo" class="ball"></div>
// 클릭한 위치로 공을 이동시킵니다:
const f = document.getElementById("foo");
document.addEventListener("click", (ev) => {
  f.style.transform = `translateY(${ev.clientY - 25}px)`;
  f.style.transform += `translateX(${ev.clientX - 25}px)`;
});

만약 CSS 트랜지션이 없다면 클릭할 때마다 공이 그 위치로 순간이동하겠죠. 하지만 CSS를 사용하면 이 자바스크립트의 동작을 아주 부드럽게 덧칠할 수 있습니다. 요소에 트랜지션만 추가해 주면 모든 변화가 부드럽게 일어납니다:

.ball {
  border-radius: 25px;
  width: 50px;
  height: 50px;
  background: #cc0000;
  position: absolute;
  top: 0;
  left: 0;
  transition: transform 1s; /* 마법의 한 줄! JS로 위치를 바꿔도 1초에 걸쳐 부드럽게 날아갑니다 */
}

트랜지션의 시작과 완료 감지하기 (Detecting the start and completion of a transition)

자바스크립트에서 애니메이션 실행이 끝났다는 것을 감지하고 싶다면 transitionend 이벤트를 사용할 수 있습니다. 이 이벤트의 핸들러에 전달되는 매개변수는 TransitionEvent 객체인데, 일반적인 Event 객체 외에 두 가지 유용한 프로퍼티가 추가되어 있습니다:

  • propertyName
    • 방금 트랜지션이 끝난 CSS 속성의 이름(문자열)을 알려줍니다.
  • elapsedTime
    • 이벤트가 발생했을 때 트랜지션이 실행된 총 시간을 초(seconds) 단위의 실수형(float)으로 알려줍니다. 이 값은 transition-delay에 설정된 지연 시간의 영향을 받지 않습니다(실제 움직인 시간만 잼).

여느 때처럼 addEventListener() 메서드를 사용해 이 이벤트를 모니터링할 수 있습니다:

el.addEventListener("transitionend", updateTransition);

💡 강사의 실무 팁 3: React에서의 트랜지션 종료 이벤트
React 환경에서 개발하실 때 이 기능을 쓰고 싶다면, JSX 태그 안에 onTransitionEnd={핸들러함수}를 달아주시면 됩니다! 슬라이드 메뉴나 툴팁이 화면에서 완전히 사라진 직후에 특정 상태(State)를 변경하고 싶을 때 이 이벤트가 아주 제격입니다.

트랜지션이 '시작'되는 시점을 감지하고 싶다면, 같은 방식으로 transitionrun(지연 시간이 시작되기 전, 즉 트랜지션이 '발동'될 때 발생)과 transitionstart(지연 시간이 모두 끝나고 진짜로 움직이기 시작할 때 발생) 이벤트를 사용하면 됩니다:

el.addEventListener("transitionrun", signalStart);
el.addEventListener("transitionstart", signalStart);

참고 (Note):
만약 요소가 도중에 display: none이 되어버리거나 애니메이션 중이던 속성값이 엎어져버려서 트랜지션이 완료되기 전에 강제로 중단(aborted)된다면, transitionend 이벤트는 발생하지 않습니다.


명세 (Specifications)

Specification (명세)
CSS Transitions Module Level 1

함께 보기 (See also)


MDN 향상에 도움 주기 (Help improve MDN)


어떠셨나요? CSS만으로도 상태를 부드럽게 이어주는 트랜지션의 강력함이 느껴지시나요? 특히 allow-discrete@starting-style 같은 최신 문법들은 모던 웹 개발자라면 반드시 챙겨가야 할 강력한 무기입니다.

포트폴리오 작업을 하시면서 책 소개 카드의 크기를 키우거나, 설명 모달 창을 띄울 때 이 트랜지션 기법들을 꼭 한번 적용해 보세요! 혹시 CSS 키프레임 애니메이션(Keyframes)과 트랜지션 중 어느 걸 써야 할지 고민되거나 헷갈리는 부분이 있으신가요?

profile
프론트에_가까운_풀스택_개발자

0개의 댓글