icon
4장 : CSS 고급 기법

CSS 애니메이션과 트랜지션


3장까지 우리는 HTML로 웹 페이지의 구조를 잡고, CSS로 스타일과 레이아웃을 꾸미는 방법을 익혔습니다. 이제 여러분의 웹 페이지에 생명을 불어넣을 차례입니다. 단순히 정적인 정보를 보여주는 것을 넘어, 요소들이 부드럽게 움직이고 변화하며 사용자에게 시각적인 피드백을 제공한다면, 웹 페이지는 훨씬 더 매력적이고 사용자 친화적으로 변할 것입니다.

이번 장에서는 CSS만으로 웹 요소에 동적인 움직임을 부여하는 두 가지 강력한 기법인 CSS 트랜지션(Transition)CSS 애니메이션(Animation) 에 대해 학습합니다. 트랜지션은 속성값이 변할 때 부드러운 전환 효과를, 애니메이션은 여러 단계의 복잡한 움직임을 제어할 수 있게 해줍니다. 이들을 통해 웹 페이지의 사용자 경험(UX)을 크게 향상시키고, 시각적인 즐거움을 더할 수 있습니다.


CSS 트랜지션 (Transition)

트랜지션은 CSS 속성값이 변할 때, 그 변화가 즉시 일어나는 대신 지정된 시간 동안 점진적으로(부드럽게) 일어나도록 하는 기능입니다. 주로 사용자의 마우스 오버(:hover), 클릭(:active), 포커스(:focus) 등 특정 이벤트에 반응하여 요소의 상태가 변할 때 유용하게 사용됩니다.

트랜지션 관련 주요 속성

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

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

    • all (기본값): 모든 CSS 속성에 트랜지션 적용
    • width, height, background-color, transform, opacity 등 특정 속성 지정
    • 여러 속성 지정 시 쉼표(,)로 구분
    .box {
        transition-property: width; /* 너비 변화에만 트랜지션 적용 */
        transition-property: background-color, transform; /* 배경색과 변형에 트랜지션 적용 */
        transition-property: all; /* 모든 속성 변화에 트랜지션 적용 */
    }
  2. transition-duration: 트랜지션이 완료되는 데 걸리는 시간을 지정합니다.

    • s (초) 또는 ms (밀리초) 단위를 사용합니다.
    • 0초는 기본값으로, 트랜지션 없이 즉시 변화합니다.
    .box {
        transition-duration: 0.5s; /* 0.5초 동안 변화 */
        transition-duration: 500ms; /* 500밀리초 동안 변화 (0.5초와 동일) */
    }
  3. 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; /* 시작과 끝이 부드러운 변화 */
    }
  4. 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 요소에 적용하려면 다음 속성들을 사용합니다.

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

  2. animation-duration: 한 번의 애니메이션 주기가 완료되는 데 걸리는 시간을 지정합니다. (s 또는 ms, 필수)

  3. animation-timing-function: 애니메이션 속도의 변화 패턴을 지정합니다. (트랜지션과 동일)

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

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

    • 1 (기본값): 한 번만 재생
    • infinite: 무한 반복
    • 특정 숫자: 지정된 횟수만큼 반복
    .element {
        animation-iteration-count: 3; /* 3번 반복 */
        animation-iteration-count: infinite; /* 무한 반복 */
    }
  6. animation-direction: 애니메이션의 재생 방향을 지정합니다.

    • normal (기본값): 0% → 100% 순으로 재생
    • reverse: 100% → 0% 순으로 재생
    • alternate: 순방향 → 역방향 → 순방향 반복 (짝수 번째는 역방향)
    • alternate-reverse: 역방향 → 순방향 → 역방향 반복
    .element {
        animation-direction: alternate; /* 왔다 갔다 반복 */
    }
  7. animation-fill-mode: 애니메이션이 끝난 후 또는 시작되기 전 요소의 스타일을 어떻게 유지할지 지정합니다.

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

애니메이션 활용 예시

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

<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 애니메이션: 언제 무엇을 쓸까?

  • 트랜지션

    • 간단한 상태 변화: 버튼 호버 효과, 메뉴 확장/축소, 탭 전환 등 두 가지 상태(시작-끝) 간의 부드러운 전환에 적합합니다.
    • 사용자 상호작용에 의해 트리거: :hover, :focus, :active, JavaScript로 클래스 추가/제거 등 이벤트에 의해 속성값이 변할 때 주로 사용합니다.
    • 코드가 비교적 간결합니다.
  • 애니메이션

    • 복잡한 다단계 움직임: 로딩 스피너, 슬라이드쇼, 특정 경로를 따라 움직이는 요소, 무한 반복되는 시각 효과 등 여러 프레임을 거치는 복잡한 움직임에 적합합니다.
    • 자동으로 시작/반복: 페이지 로딩 시 자동으로 시작되거나, 무한 반복되는 효과에 주로 사용됩니다.
    • @keyframes를 통해 각 프레임을 세밀하게 제어할 수 있습니다.

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


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

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

  1. 프로젝트 폴더 구조

    dynamic_web.html
    motion.css
  2. 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>
  3. 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;
    }
  4. 결과 확인

    • 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 등 다양한 속성으로 애니메이션의 재생 방식을 제어할 수 있습니다. 이는 로딩 효과나 반복적인 시각 효과 등 더 복잡한 움직임을 구현하는 데 적합합니다.

이 두 가지 기법을 적절히 활용함으로써 여러분의 웹 페이지는 단순한 정보 전달을 넘어 사용자에게 시각적인 즐거움과 더 나은 인터랙션을 제공하는 동적인 경험을 선사할 수 있게 될 것입니다.