본문으로 건너뛰기

안동민 개발노트

본문 시작

CSS 애니메이션과 트랜지션

상태 변화에는 transition을, 다단계 움직임에는 keyframes animation을 적용해 자연스러운 시각 피드백을 만듭니다.

3장까지 우리는 HTML로 웹 페이지 구조를 잡고, CSS로 스타일과 레이아웃을 꾸미는 방법을 익혔습니다.

이제 웹 페이지에 전환과 애니메이션 효과를 추가해 봅니다.

단순히 정적인 정보를 보여주는 것을 넘어, 요소가 부드럽게 움직이고 변화하며 사용자에게 시각적 피드백을 제공하면 웹 페이지는 훨씬 더 매력적이고 사용자 친화적으로 변합니다.

이번 장에서는 CSS만으로 동적 움직임을 구현하는 두 기법, CSS 트랜지션(Transition)CSS 애니메이션(Animation)을 다룹니다.

트랜지션은 속성값이 변할 때 부드러운 전환 효과를 만들고, 애니메이션은 여러 단계의 복잡한 움직임을 제어할 수 있게 해줍니다.

이 두 기법을 통해 웹 페이지의 사용자 경험(UX)을 높이고 시각적인 즐거움을 더할 수 있습니다.

상태 전환과 keyframe timeline 선택

FLOWCHART · B99 WEB FUNDAMENTALS

상태 전환과 keyframe timeline 선택

움직임이 실제 상태 피드백에 필요한지와 reduced-motion 선호를 먼저 확인한다. 두 상태 값 사이의 변화는 transition, 다단계·자동 시작·반복 timeline은 animation을 사용하고, 실행 중 target 변경과 cancel 경로까지 설계한다.

상태 전환과 keyframe timeline 선택 choose no motion, a reduced alternative, transition, or keyframe animation from feedback need, reduced-motion preference, intermediate stages, autonomy, and repetition, then handle finish or cancellation MOTION NEED상태·피드백 요구trigger·purpose·interruption PURPOSE움직임이 필요한가?상태 이해에 기여 PREFERENCEreduced motion?사용자·OS 설정 TIMELINE다단계·자동·반복?중간 keyframe 필요 NO MOTION즉시 상태 적용색·문구·아이콘으로 피드백 REDUCED축소·대체거리·반복 제거, 의미 유지 ANIMATION@keyframes timeline다단계·iteration·direction TRANSITION두 상태 값 전환property·duration·easing START → DELAY → RUNNING → FINISHtarget 변경: reverse/restart · 요소 제거·name 변경: cancel · cleanup 수행 NOYESYESNOYESNO

선택 기준

No motion — 움직임이 의미를 더하지 않으면 즉시 상태와 비동작 신호를 적용합니다. · Transition — hover·focus·class toggle의 두 property 값을 duration·easing으로 보간합니다. · Animation — 중간 keyframe, 자동 시작·반복, direction·fill mode가 필요할 때 선택합니다.

선호와 수명

Reduced motion — 의미는 유지하고 이동·반복·자동 재생을 줄이거나 즉시 전환합니다. · 중단 처리 — start/run/finish와 함께 reverse·restart·cancel 및 cleanup을 처리합니다.

transition과 animation 모두 모든 속성을 같은 비용으로 움직이지 않는다. 가능하면 transform·opacity를 우선하고 레이아웃 변경과 사용자 선호를 함께 검증한다.


CSS 트랜지션 (Transition)

CSS 애니메이션과 트랜지션에서는 스타일 규칙, 레이아웃 계산, 화면 반영 결과를 정리합니다.

트랜지션은 CSS 속성값이 변할 때, 그 변화가 즉시 일어나는 대신 지정된 시간 동안 점진적으로(부드럽게) 일어나도록 하는 기능입니다.

주로 사용자의 마우스 오버(:hover), 클릭(:active), 포커스(:focus) 등 특정 이벤트에 반응하여 요소의 상태가 변할 때 유용하게 사용됩니다.

트랜지션 관련 주요 속성

트랜지션을 적용하려면 주로 다음 네 가지 속성을 사용합니다.

transition-property: 트랜지션 효과를 적용할 CSS 속성을 지정합니다.

  • all (기본값): 모든 CSS 속성에 트랜지션 적용
  • width, height, background-color, transform, opacity 등 특정 속성 지정
  • 여러 속성 지정 시 쉼표(,)로 구분
.box {
    transition-property: width; /* 너비 변화에만 트랜지션 적용 */
    transition-property: background-color, transform; /* 배경색과 변형에 트랜지션 적용 */
    transition-property: all; /* 모든 속성 변화에 트랜지션 적용 */
}

transition-duration: 트랜지션이 완료되는 데 걸리는 시간을 지정합니다.

  • s (초) 또는 ms (밀리초) 단위를 사용합니다.
  • 0초는 기본값으로, 트랜지션 없이 즉시 변화합니다.
.box {
    transition-duration: 0.5s; /* 0.5초 동안 변화 */
    transition-duration: 500ms; /* 500밀리초 동안 변화 (0.5초와 동일) */
}

transition-timing-function: 트랜지션 속도의 변화 패턴을 지정합니다. (가속도 곡선)

  • ease (기본값): 느리게 시작 → 빠르게 → 느리게 끝남 (부드러운 효과)
  • linear: 일정한 속도
  • ease-in: 느리게 시작 → 점차 빨라짐
  • ease-out: 빠르게 시작 → 점차 느려짐
  • ease-in-out: 느리게 시작 → 빨라짐 → 느리게 끝남 (ease와 유사하나 시작/끝이 더 극적)
  • cubic-bezier(n, n, n, n): 자신만의 커스텀 가속도 곡선을 정의 (고급)
  • steps(n, direction): n개의 단계로 뚝뚝 끊어지는 변화 (애니메이션에 유용)
.box {
    transition-timing-function: ease-in-out; /* 시작과 끝이 부드러운 변화 */
}

transition-delay: 트랜지션이 시작되기 전까지 기다릴 시간을 지정합니다.

  • s (초) 또는 ms (밀리초) 단위를 사용합니다.
.box {
    transition-delay: 0.2s; /* 0.2초 후에 트랜지션 시작 */
}

transition 단축 속성

위 네 가지 속성을 한 줄에 요약하여 작성할 수 있습니다.

순서는 중요하지 않지만, 시간을 나타내는 값이 두 개일 경우 첫 번째는 duration, 두 번째는 delay로 인식됩니다.

.box {
    /* property | duration | timing-function | delay */
    transition: all 0.5s ease-in-out 0.1s;

    /* 배경색 변화에 0.3초 ease 효과 */
    transition: background-color 0.3s ease;

    /* 너비 변화에 0.5초, 배경색 변화에 0.3초 */
    transition: width 0.5s, background-color 0.3s;
}

트랜지션 활용 예시

간단한 버튼에 마우스 오버 효과를 적용해 봅시다.

<style>
    .my-button {
        background-color: #3498db;
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        font-size: 16px;

        /* 트랜지션 적용 */
        transition: background-color 0.3s ease-out, transform 0.3s ease-out;
    }

    .my-button:hover {
        background-color: #2980b9; /* 배경색 변경 */
        transform: translateY(-3px); /* 위로 살짝 이동 */
        box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); /* 그림자 추가 */
    }
</style>

<button class="my-button">마우스를 올려보세요</button>

CSS 애니메이션 (Animation)

트랜지션이 속성 변화에 대한 부드러운 전환이라면, 애니메이션은 여러 단계에 걸쳐 다양한 속성을 원하는 시간 동안 반복적으로 제어할 수 있는 훨씬 강력한 기능입니다.

@keyframes 규칙을 사용하여 애니메이션의 각 단계를 직접 정의합니다.

@keyframes 규칙 정의

애니메이션의 이름과 각 단계(프레임)에서의 CSS 스타일을 정의합니다.

각 단계는 퍼센트(%)로 지정하며, 0% (또는 from)은 시작 상태, 100% (또는 to)는 끝 상태를 의미합니다.

중간 단계를 여러 개 지정할 수 있습니다.

@keyframes slideIn {
    0% { /* 시작 상태 */
        transform: translateX(-100%); /* 왼쪽으로 완전히 벗어남 */
        opacity: 0;
    }
    50% { /* 50% 지점 */
        opacity: 0.5;
    }
    100% { /* 끝 상태 */
        transform: translateX(0); /* 원래 위치로 돌아옴 */
        opacity: 1;
    }
}

@keyframes bounce {
    0%, 20%, 50%, 80%, 100% {
        transform: translateY(0);
    }
    40% {
        transform: translateY(-30px);
    }
    60% {
        transform: translateY(-15px);
    }
}

애니메이션 관련 주요 속성

정의된 @keyframes 애니메이션을 HTML 요소에 적용하려면 다음 속성들을 사용합니다.

animation-name: 적용할 @keyframes 애니메이션의 이름을 지정합니다.

(필수)

animation-duration: 한 번의 애니메이션 주기가 완료되는 데 걸리는 시간을 지정합니다.

(s 또는 ms, 필수)

animation-timing-function: 애니메이션 속도의 변화 패턴을 지정합니다.

(트랜지션과 동일)

animation-delay: 애니메이션이 시작되기 전까지 기다릴 시간을 지정합니다.

animation-iteration-count: 애니메이션이 반복될 횟수를 지정합니다.

  • 1 (기본값): 한 번만 재생
  • infinite: 무한 반복
  • 특정 숫자: 지정된 횟수만큼 반복
.element {
animation-iteration-count: 3; /* 3번 반복 */
animation-iteration-count: infinite; /* 무한 반복 */
}

animation-direction: 애니메이션의 재생 방향을 지정합니다.

  • normal (기본값): 0% → 100% 순으로 재생
  • reverse: 100% → 0% 순으로 재생
  • alternate: 순방향 → 역방향 → 순방향 반복 (짝수 번째는 역방향)
  • alternate-reverse: 역방향 → 순방향 → 역방향 반복
.element {
    animation-direction: alternate; /* 왔다 갔다 반복 */
}

animation-fill-mode: 애니메이션이 끝난 후 또는 시작되기 전 요소의 스타일을 어떻게 유지할지 지정합니다.

  • none (기본값): 애니메이션 시작 전/후에 원래 스타일로 돌아감.
  • forwards: 애니메이션이 끝난 후 마지막 @keyframes 상태를 유지.
  • backwards: 애니메이션 시작 전 0% (또는 from) 상태를 유지. (딜레이가 있을 경우)
  • both: forwardsbackwards 모두 적용.
.element {
    animation-fill-mode: forwards; /* 애니메이션 끝난 상태 유지 */
}

animation-play-state: 애니메이션의 재생 상태를 제어합니다.

  • running (기본값): 재생 중
  • paused: 일시 정지
.element:hover {
    animation-play-state: paused; /* 마우스 오버 시 애니메이션 일시 정지 */
}

animation 단축 속성

위 모든 속성을 한 줄에 요약하여 작성할 수 있습니다.

순서가 중요하며, 필수 값인 animation-nameanimation-duration은 반드시 포함되어야 합니다.

.element {
    /* name | duration | timing-function | delay | iteration-count | direction | fill-mode | play-state */
    animation: slideIn 1s ease-out 0.5s infinite alternate forwards;
}

animation 단축 속성은 이름, 지속 시간, timing function, 지연, 반복 횟수 같은 실행 제어 값을 함께 설정합니다.

애니메이션 활용 예시

웹 페이지 로딩 시 나타나는 요소 또는 무한 반복되는 로딩 애니메이션을 만들어 봅시다.

<style>
    /* 애니메이션 정의 */
    @keyframes fadeInSlideUp {
        0% {
            opacity: 0;
            transform: translateY(20px);
        }
        100% {
            opacity: 1;
            transform: translateY(0);
        }
    }

    @keyframes rotate360 {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
    }

    .fade-in-box {
        width: 200px;
        height: 100px;
        background-color: #2ecc71; /* 에메랄드 */
        color: white;
        display: flex;
        justify-content: center;
        align-items: center;
        margin: 50px auto;
        border-radius: 8px;
        font-size: 1.2em;

        /* 애니메이션 적용 */
        animation-name: fadeInSlideUp;
        animation-duration: 0.8s;
        animation-timing-function: ease-out;
        animation-fill-mode: backwards; /* 애니메이션 시작 전 0% 상태 유지 (투명, 아래로) */
        animation-delay: 0.5s; /* 0.5초 후에 시작 */
    }

    .spinner {
        width: 50px;
        height: 50px;
        border: 5px solid #f3f3f3; /* 연한 회색 테두리 */
        border-top: 5px solid #3498db; /* 파란색 상단 테두리 */
        border-radius: 50%; /* 원형 */
        margin: 30px auto;

        /* 애니메이션 적용 */
        animation: rotate360 1s linear infinite; /* 1초 동안 무한히 선형 회전 */
    }
</style>

<div class="fade-in-box">나타나는 박스</div>
<div class="spinner"></div>

트랜지션 vs 애니메이션: 언제 무엇을 쓸까?

이 절의 통합 다이어그램은 상태 변화의 필요성과 중간 단계·반복 여부를 기준으로 transition과 animation을 고르는 질문을 정리합니다.

  • 트랜지션
    • 간단한 상태 변화: 버튼 호버 효과, 메뉴 확장/축소, 탭 전환 등 두 가지 상태(시작-끝) 간의 부드러운 전환에 적합합니다.
    • 사용자 상호작용에 의해 트리거: :hover, :focus, :active, JavaScript로 클래스 추가/제거 등 이벤트에 의해 속성값이 변할 때 주로 사용합니다.
    • 코드가 비교적 간결합니다.
  • 애니메이션
    • 복잡한 다단계 움직임: 로딩 스피너, 슬라이드쇼, 특정 경로를 따라 움직이는 요소, 무한 반복되는 시각 효과 등 여러 프레임을 거치는 복잡한 움직임에 적합합니다.
    • 자동으로 시작/반복: 페이지 로딩 시 자동으로 시작되거나, 무한 반복되는 효과에 주로 사용됩니다.
    • @keyframes를 통해 각 프레임을 세밀하게 제어할 수 있습니다.

결론: 간단한 UI 인터랙션에는 트랜지션을, 복잡하거나 반복적인 시각 효과에는 애니메이션을 사용한다고 생각하면 됩니다.


실습: 웹 페이지에 동적인 효과 추가하기

배운 트랜지션과 애니메이션 속성들을 활용하여 실제 웹 페이지에 동적인 효과를 추가해 봅시다.

프로젝트 폴더 구조
dynamic_web.html
motion.css
dynamic_web.html 파일 작성
dynamic_web.html
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS 애니메이션과 트랜지션 실습</title>
    <link rel="stylesheet" href="css/motion.css">
</head>
<body>
    <header>
        <h1 class="page-title">동적인 웹 페이지 만들기</h1>
        <p class="subtitle">CSS Transition과 Animation의 힘!</p>
    </header>

    <main>
        <section class="transition-section">
            <h2>1. CSS 트랜지션 예시</h2>
            <div class="button-container">
                <button class="hover-button">마우스 오버해보세요</button>
                <div class="box-grow">크기/색깔 변환 박스</div>
            </div>
        </section>

        <section class="animation-section">
            <h2>2. CSS 애니메이션 예시</h2>
            <div class="loading-spinner"></div>
            <div class="bouncing-ball"></div>
            <div class="slide-in-text">짜잔! 등장하는 텍스트!</div>
        </section>
    </main>

    <footer>
        <p>&copy; 2025 CSS Motion Practice. 모든 권리 보유.</p>
    </footer>
</body>
</html>
css/motion.css 파일 작성
css/motion.css
/* 기본 설정 */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: #f0f2f5;
    color: #333;
    line-height: 1.6;
    padding-bottom: 50px;
}

header {
    background-color: #34495e;
    color: white;
    text-align: center;
    padding: 30px 20px;
    box-shadow: 0 3px 6px rgba(0,0,0,0.2);
    margin-bottom: 30px;
}
.page-title {
    font-size: 2.8em;
    margin-bottom: 5px;
}
.subtitle {
    font-size: 1.2em;
    font-style: italic;
}

main {
    max-width: 900px;
    margin: 0 auto;
    padding: 0 20px;
}

section {
    background-color: white;
    padding: 30px;
    margin-bottom: 30px;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
section h2 {
    color: #2980b9;
    font-size: 2em;
    margin-bottom: 25px;
    text-align: center;
}

/* ------------------------------------------- */
/* 1. CSS 트랜지션 예시 */
/* ------------------------------------------- */
.button-container {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 40px;
    flex-wrap: wrap;
    padding: 20px;
}

.hover-button {
    background-color: #2ecc71; /* 에메랄드 */
    color: white;
    padding: 15px 30px;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: 1.1em;
    font-weight: bold;
    outline: none; /* 포커스 시 아웃라인 제거 */

    /* 트랜지션 적용: 모든 변화에 0.3초 ease-out 효과 */
    transition: all 0.3s ease-out;
}

.hover-button:hover {
    background-color: #27ae60; /* 진한 에메랄드 */
    transform: scale(1.05) translateY(-5px); /* 확대 및 살짝 위로 이동 */
    box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2); /* 그림자 진하게 */
}

.box-grow {
    width: 150px;
    height: 150px;
    background-color: #e74c3c; /* 벽돌색 */
    color: white;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 15px;
    font-size: 1.1em;
    cursor: pointer;

    /* 트랜지션 적용: 너비, 높이, 배경색, border-radius에 0.4초 ease 효과 */
    transition: width 0.4s ease, height 0.4s ease,
                background-color 0.4s ease, border-radius 0.4s ease;
}

.box-grow:hover {
    width: 200px; /* 너비 증가 */
    height: 200px; /* 높이 증가 */
    background-color: #c0392b; /* 배경색 변경 */
    border-radius: 50%; /* 원형으로 변경 */
}

/* ------------------------------------------- */
/* 2. CSS 애니메이션 예시 */
/* ------------------------------------------- */

/* 로딩 스피너 애니메이션 */
@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

.loading-spinner {
    width: 60px;
    height: 60px;
    border: 6px solid #f3f3f3; /* 밝은 회색 테두리 */
    border-top: 6px solid #3498db; /* 파란색 상단 테두리 */
    border-radius: 50%;
    margin: 30px auto; /* 중앙 정렬 */

    /* 애니메이션 적용 */
    animation: spin 1.2s linear infinite; /* 1.2초 동안 선형 무한 회전 */
}

/* 통통 튀는 공 애니메이션 */
@keyframes bounce {
    0%, 100% { transform: translateY(0); } /* 시작과 끝은 제자리 */
    50% { transform: translateY(-50px); } /* 중간에 위로 50px */
}

.bouncing-ball {
    width: 50px;
    height: 50px;
    background-color: #f1c40f; /* 노란색 */
    border-radius: 50%;
    margin: 50px auto;
    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);

    /* 애니메이션 적용 */
    animation: bounce 1.5s ease-in-out infinite alternate; /* 1.5초 동안 ease-in-out으로 무한히 왕복 */
}

/* 슬라이드인 텍스트 애니메이션 */
@keyframes slideInFromLeft {
    0% {
        transform: translateX(-100%); /* 왼쪽 밖에서 시작 */
        opacity: 0;
    }
    100% {
        transform: translateX(0); /* 원래 위치로 이동 */
        opacity: 1;
    }
}

.slide-in-text {
    font-size: 2.5em;
    font-weight: bold;
    color: #27ae60;
    text-align: center;
    margin-top: 50px;
    opacity: 0; /* 초기에는 투명하게 */

    /* 애니메이션 적용 */
    animation: slideInFromLeft 1s ease-out forwards; /* 1초 동안 ease-out으로 재생 후 마지막 상태 유지 */
    animation-delay: 0.5s; /* 0.5초 후에 애니메이션 시작 */
}

/* 푸터 */
footer {
    background-color: #34495e;
    color: #ecf0f1;
    text-align: center;
    padding: 20px 0;
    margin-top: 50px;
    font-size: 0.9em;
}
결과 확인
  • Live Server를 통해 dynamic_web.html 파일을 열어보세요.
  • 트랜지션 섹션
    • hover-button에 마우스를 올렸다 내렸다 하며 배경색 변화와 크기/위치/그림자 변화가 부드럽게 일어나는 것을 확인하세요.
    • box-grow에 마우스를 올렸다 내렸다 하며 너비, 높이, 배경색, 테두리 반경(원형으로)이 부드럽게 전환되는 것을 확인하세요.
  • 애니메이션 섹션
    • 페이지를 로드하자마자 loading-spinner가 계속 회전하는 것을 확인하세요.
    • bouncing-ball이 통통 튀어 오르는 동작을 무한 반복하는 것을 확인하세요.
    • 페이지 로드 후 잠시 뒤(animation-delay) slide-in-text가 왼쪽에서 부드럽게 나타나는 것을 확인하세요.

이번 장에서는 CSS만으로 웹 페이지에 동적인 효과를 부여하는 강력한 두 가지 기법인 CSS 트랜지션(Transition)CSS 애니메이션(Animation)을 학습했습니다.

  • 트랜지션은 CSS 속성값이 변할 때 부드러운 전환 효과를 주는 데 사용되며, 주로 사용자 상호작용에 의해 트리거되는 간단한 상태 변화에 적합합니다. transition-property, transition-duration, transition-timing-function, transition-delay 속성들을 통해 전환 효과를 세밀하게 제어할 수 있습니다.
  • 애니메이션@keyframes 규칙을 통해 여러 단계의 복잡한 움직임을 정의하고, animation-name, animation-duration, animation-iteration-count, animation-direction, animation-fill-mode 등 다양한 속성으로 애니메이션의 재생 방식을 제어할 수 있습니다. 이는 로딩 효과나 반복적인 시각 효과 등 더 복잡한 움직임을 구현하는 데 적합합니다.

트랜지션과 애니메이션을 적절히 사용하면 상태 변화와 사용자 상호작용을 더 명확하게 표현할 수 있습니다.