AD JB Toolbox 01

CSS 강좌 / @keyframes 애니메이션과 움직임 줄이기

@keyframes는 애니메이션의 여러 시점에서 사용할 CSS 값을 정의하고, animation은 그 변화를 언제·얼마나·어떤 방향으로 재생할지 정합니다. 사용자의 호버 없이 실행하거나 중간 상태와 반복이 필요한 효과에 적합합니다. 움직임은 내용을 읽거나 조작하는 데 방해되지 않아야 하며, 줄이기 설정에서도 필요한 정보를 바로 볼 수 있게 기본 상태를 작성합니다.

transition과 animation을 구분하기

기준 transition animation
시작 조건 호버·초점·클래스 변경 등으로 값이 바뀔 때 animation이 적용되고 지연 시간이 지나면
상태 정의 바뀌기 전과 후의 CSS 값 키프레임에서 시작·중간·끝 값 지정
반복과 방향 상태 변경을 따라 진행 횟수·방향·정지 상태를 별도 지정

버튼의 배경색이 바뀌는 정도라면 transition이 간단합니다. 알림이 처음 나타나는 효과나 여러 단계를 거치는 시각적 설명에는 animation을 검토할 수 있습니다. 같은 요소의 같은 속성을 두 기능으로 동시에 제어하면 어느 값이 적용되는지 추적하기 어려워지므로 이 실습에서는 역할을 나눕니다. 상태 변경 전후의 효과로 충분하다면 transform과 transition의 상태 변화를 사용한 단순한 전환부터 검토하세요.

키프레임과 재생 설정 읽기

키프레임의 from은 0%, to는 100%에 해당합니다. 중간 상태가 필요하면 50%처럼 진행 비율을 추가합니다. 키프레임 이름만 선언해도 재생되지는 않으며 요소의 animation-name과 연결해야 합니다.

@keyframes travel {
  0% { transform: translateX(0); }
  50% { transform: translateX(3rem); }
  100% { transform: translateX(6rem); }
}
.marker { animation: travel 4s linear 1s 1 normal forwards; }

이 부분 코드는 아래 전체 예제에서 같은 이름의 키프레임과 .marker 설정을 짧게 표현한 것입니다. 4s는 한 번 재생하는 데 걸리는 시간이고 1s는 시작 지연입니다. 지속 시간을 지정하지 않으면 기본값 0초라서 움직이는 과정을 관찰하기 어렵습니다. 처음에는 긴 속성으로 나누어 작성하면 시간과 횟수를 혼동하는 일을 줄일 수 있습니다.

속성 이 예제의 값 바꾸어 볼 점
animation-duration 4s 한 번의 재생 시간
animation-timing-function linear 일정한 진행과 ease 곡선의 차이
animation-delay 1s 시작 전 대기 시간
animation-iteration-count 1 재생 횟수; infinite는 무한 반복
animation-direction normal 정방향·역방향·교대 재생
animation-fill-mode forwards 재생 밖 시간에 적용할 값
animation-play-state 기본값 running paused로 현재 진행을 일시 정지

비율이 같은 간격으로 적혀 있어도 실제 위치 변화는 시간 함수에 따라 달라집니다. 이번 실습은 중간 위치를 확인하기 쉬운 linear를 사용합니다. 키프레임 작성과 연결은 MDN @keyframes 문서를 참고하세요.

반복 방향과 마지막 상태를 정확히 이해하기

normal은 처음에서 끝으로, reverse는 끝에서 처음으로 진행합니다. alternate는 첫 회에 정방향, 다음 회에 역방향으로 번갈아 재생합니다. 반복 횟수가 2이고 alternate라면 마지막은 처음 키프레임에 도착합니다.

forwards는 항상 100% 키프레임을 유지하는 설정이 아닙니다. 재생 방향과 횟수에 따라 실제 마지막에 도달한 키프레임의 값을 유지합니다. 예제의 정방향 1회는 6rem 위치를, 역방향 1회는 0 위치를, alternate 2회도 0 위치를 유지합니다. 이 설명은 정수 횟수의 완료된 재생을 기준으로 하며, 소수 횟수는 중간 진행에서 끝날 수 있습니다. MDN fill-mode 설명에 방향별 조건이 정리되어 있습니다.

fill-mode 지연 중 종료 후
none 기본 CSS 기본 CSS
forwards 기본 CSS 마지막에 재생한 키프레임
backwards 처음 재생할 키프레임 기본 CSS
both 처음 재생할 키프레임 마지막에 재생한 키프레임

기본 CSS 값과 키프레임 끝 값이 같으면 none과 forwards의 차이가 눈에 보이지 않을 수 있습니다. 아래 이동 박스는 기본 위치를 1rem, 시작을 0, 끝을 6rem으로 다르게 두어 차이가 드러나게 만들었습니다. 반면 꼭 읽어야 하는 안내는 애니메이션을 제거했을 때 보이는 완성 상태를 기본값으로 둡니다.

전체 예제와 한 가지 설정씩 바꾸는 실습

다음 코드를 UTF-8의 animation-lab.html로 저장하고 브라우저로 엽니다. 위쪽 안내는 짧게 등장하고, 아래 장식 박스는 1초 뒤 이동을 시작해 4초 동안 움직입니다. 값 수정 후 파일을 저장하고 페이지를 새로고침하면 처음부터 비교할 수 있습니다.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>키프레임과 종료 상태 실습</title>
  <style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; padding: 1rem; color: #183044; font-family: sans-serif; line-height: 1.6; }
main { max-width: 46rem; margin-inline: auto; }
h1 { font-size: 1.5rem; } h2 { font-size: 1.2rem; }
button, input { font: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 3px solid #164f73; outline-offset: 3px; }
.notice { padding: 1rem; border: 1px solid #90bdd8; border-radius: .5rem; background: #eaf4fa;
  opacity: 1; transform: none; animation: appear 400ms ease-out; }
@keyframes appear {
  from { opacity: 0; transform: translateY(.5rem); }
  to { opacity: 1; transform: translateY(0); }
}
.track { margin-block: 1rem; padding: 1rem; border: 2px dashed #8a9ba7; }
.marker { width: 2rem; height: 2rem; border-radius: .25rem; background: #166b92;
  transform: translateX(1rem);
  animation-name: travel; animation-duration: 4s; animation-timing-function: linear;
  animation-delay: 1s; animation-iteration-count: 1; animation-direction: normal;
  animation-fill-mode: forwards; }
@keyframes travel {
  0% { transform: translateX(0); background-color: #166b92; }
  50% { transform: translateX(3rem); background-color: #6a3989; }
  100% { transform: translateX(6rem); background-color: #28633b; }
}
#pause:checked ~ .track .marker { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .notice, .marker { animation: none; }
}
  </style>
</head>
<body>
<main>
<h1>등장과 이동 확인</h1>
<p class="notice">이 안내는 애니메이션이 없어도 읽을 수 있습니다.</p>
<h2>종료 상태 비교</h2>
<p>이동은 불러온 뒤 1초 후에 시작합니다. 새로고침해 다시 비교하세요.</p>
<input id="pause" type="checkbox"><label for="pause">이동 일시 정지</label>
<div class="track"><div class="marker" aria-hidden="true"></div></div>
<p>색과 위치는 실습용 장식입니다. 중요한 내용은 이 문장처럼 움직임과 별도로 제공합니다.</p>
</main>
</body>
</html>
  1. 기본 설정에서는 박스가 지연 중 1rem 위치에 있다가 시작 시 0으로 가서 이동하고, 종료 후 6rem 위치에 남습니다. 지연 중 값과 시작 값의 차이를 확인합니다.
  2. animation-fill-mode만 none으로 바꾸고 새로고침합니다. 끝난 뒤 기본 위치 1rem과 기본 파란색으로 돌아갑니다. 다시 forwards로 복원합니다.
  3. fill-mode만 both로 바꿉니다. 지연 중에도 시작 위치 0이 적용됩니다. 확인 후 forwards로 되돌립니다.
  4. 횟수는 1로 두고 방향만 reverse로 바꿉니다. 종료 후 0 위치에 남는 것을 확인한 뒤 normal로 복원합니다.
  5. 방향을 alternate로 바꾸고 횟수는 1로 유지한 결과를 확인합니다. 그 상태에서 횟수만 2로 바꾸면 돌아오는 두 번째 재생이 생깁니다. 확인 후 횟수 1, 방향 normal로 복원합니다.
  6. 새로고침 직후 일시 정지 체크박스를 켜고 잠시 기다립니다. 해제하면 중단했던 위치부터 진행합니다. 이것은 처음부터 다시 재생하는 기능과 다릅니다.

움직임을 줄이고 내용은 유지하기

감소 설정에서는 안내와 장식 박스의 animation을 없앱니다. 안내는 기본값이 opacity: 1이므로 계속 읽을 수 있고, 박스는 기본 위치 1rem에 표시됩니다. 종료 키프레임이나 forwards에만 읽을 수 있는 상태를 맡기면 animation이 없을 때 내용이 사라질 수 있습니다.

개발자 도구의 Rendering 패널이나 운영체제에서 움직임 감소를 설정하고 새로고침하세요. 두 요소 모두 움직이지 않고 내용은 보여야 합니다. 설정 확인 방법은 MDN prefers-reduced-motion 안내를 참고하고, 비교를 마치면 재현 설정을 기본값으로 복원합니다. 움직임을 없앤 상태에서도 키보드·확대 조건에서 레이아웃 점검 항목에 따라 잘림과 조작 가능 여부를 확인하세요.

무한 반복을 추가하기 전에 움직임의 목적과 멈출 방법을 판단하세요. 장식만을 위해 계속 움직이는 UI는 주의를 분산시킬 수 있습니다. 이 예제는 유한 횟수를 사용하며, 색이나 움직임만으로 중요한 정보를 전달하지 않습니다. 동작이 없을 때는 이름의 철자·지속 시간·감소 설정을 확인하고, 종료 후 값이 예상과 다를 때는 방향·횟수·fill-mode·기본 CSS를 순서대로 비교하면 원인을 좁힐 수 있습니다.

같은 카테고리의 다른 글
CSS 강좌 / 큰 스타일시트 정리하기: 파일 구성·중첩·레이어

CSS 강좌 / 큰 스타일시트 정리하기: 파일 구성·중첩·레이어

역할별 CSS 파일 연결과 네이티브 중첩, 캐스케이드 레이어를 실행 가능한 작은 프로젝트로 익힙니다. 선택자 충돌을 비교하고 원래 설정으로 복원하는 실습을 제공합니다.

CSS 강좌 / 링크 꾸미는 방법

CSS 강좌 / 링크 꾸미는 방법

링크의 기본 밑줄과 방문·호버·활성 상태를 설정하고 키보드 포커스를 표시합니다. 두 파일로 방문 이력과 Tab·Enter 동작을 확인하며 상태 규칙이 겹칠 때의 결과를 설명합니다.

CSS 강좌 / CSS를 HTML에 적용시키는 방법

CSS 강좌 / CSS를 HTML에 적용시키는 방법

인라인·내부·외부 CSS의 작성 위치를 비교하고, 두 HTML 페이지가 하나의 스타일시트를 공유하도록 구성합니다. 폴더 위치에 따른 경로와 CSS가 적용되지 않을 때의 확인 순서도 설명합니다.

CSS 강좌 / Flexbox로 요소를 한 방향에 배치하기

CSS 강좌 / Flexbox로 요소를 한 방향에 배치하기

Flexbox의 직접 자식, 주축과 교차축, row·column·reverse의 차이를 전체 예제로 익힙니다. 초기 크기와 키보드 순서를 비교하면서 배치가 달라지는 이유를 확인합니다.

CSS / Tutorial / 마우스 호버 효과 / 다른 이미지 보여주는 방법

CSS / Tutorial / 마우스 호버 효과 / 다른 이미지 보여주는 방법

이미지에 마우스를 올렸을 때 다른 이미지가 나타나는 효과를 CSS로 만들어보겠습니다. 다음과 같이 이미지 두 개를 넣고 div로 감쌉니다.

CSS / Tutorial / 마우스 호버 효과 / 서서히 길어지는 선 만드는 방법

CSS / Tutorial / 마우스 호버 효과 / 서서히 길어지는 선 만드는 방법

마우스를 올리면 선이 그려지는 효과를 만들어봅니다. 다음과 같이 사각형을 만듭니다. :before를 이용하여 선이 시작하는 위치를 정합니다. position 속성으로 선 위에 선을 그릴 수 있도록 설정합니다.

CSS 강좌 / display와 기본 배치 흐름 이해하기

CSS 강좌 / display와 기본 배치 흐름 이해하기

block·inline·inline-block의 줄바꿈과 크기 적용을 같은 요소로 비교합니다. display: none과 visibility: hidden의 공간 차이, 인라인 이미지의 크기 예외를 실행하며 확인합니다.

CSS 강좌 / 표 꾸미기 / 배경색

CSS 강좌 / 표 꾸미기 / 배경색

배경색은 background-color 속성으로 만듭니다. table, tr, th, td, thead, tbody, tfoot에 적용할 수 있습니다. 다음 표를 기본으로 하고, 배경색을 여러 곳에 추가해보겠습니다.

CSS 강좌 / 배경색과 배경 이미지 설정하기

CSS 강좌 / 배경색과 배경 이미지 설정하기

실습용 이미지를 내려받아 배경색과 배경 이미지 경로를 설정합니다. cover·contain의 잘림과 빈 공간, 반복과 위치를 비교하고 배경이 안 보일 때의 확인 순서를 설명합니다.

CSS 강좌 / 기본 선택자 - 요소, 클래스, ID, 속성

CSS 강좌 / 기본 선택자 - 요소, 클래스, ID, 속성

요소·클래스·ID·속성 선택자를 같은 HTML에 적용해 대상과 결과를 비교합니다. 복합 클래스, 공백으로 구분한 속성값, 필수 입력칸을 포함한 전체 예제와 선택자 수정 실습을 제공합니다.