GODRICH
#css애니메이션#버튼#로딩#전환효과#스크롤#대시보드#실전ui#디자인트렌드

CSS 캐릭터 애니메이션 9종 — 세탁기·집·자동차를 도형으로 움직이기

css 캐릭터 애니메이션은 세탁기·집·자동차 같은 사물을 그림 파일 한 장도 없이 색 박스 몇 개로 그려 움직이는 일입니다. 아홉 개를 순수 CSS 도형으로 만들었고, 아래 격자에서 지금 돌아갑니다.

자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip

순서는 인기순이 아니라 사물 하나가 그려지고 움직이는 데 필요한 재료의 순서입니다. 먼저 둥근 창 하나가 사물의 얼굴이 되고(01), 지붕과 굴뚝으로 집 한 채가 서고(02), 바퀴와 불빛으로 차가 다가오고(03), 글자 위를 지나가는 실루엣으로 캐릭터가 생기고(04), 기기 안의 풍경으로 화면이 깊어지고(05), 해와 그리드로 무대가 꾸며지고(06·07·08), 마지막에 통째로 하나의 세계가 된 트렁크 하우스로 맺습니다(09). css 도형 그리기는 별도 프로그램 없이 둥근 모서리와 clip-path 만으로 되는데, 아홉 개 모두 무대 안의 사각형·원·삼각형 조각이라 외부 파일이 0개입니다. 같은 사물 축에서 창문 안 풍경을 먼저 다룬 CSS 장면 애니메이션, 캔버스로 비슷한 무대를 그리는 캔버스 씬 효과가 이 편의 이웃입니다.

01세탁기 드럼 회전

정면 세탁기를 크림색 몸체·원형 도어·컨트롤 패널로 짜고 도어 안 물과 양말이 한 덩어리로 도는, 가전 제품 소개 화면용 부품입니다.

세탁기 드럼 회전
새 창에서 열기

01 · 세탁기 드럼 회전 — 측정 누적면적 3.349% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

rotateanimation-play-statescaleY

드럼은 한 그룹으로 묶어 한 바퀴

.ws__drum {
  position: absolute; inset: 0;
  animation-name: wsSpin; animation-duration: $duration;
  animation-timing-function: linear; animation-iteration-count: infinite;
}
.ws.is-pause .ws__drum { animation-play-state: paused; }

@keyframes wsSpin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
@keyframes wsBlink {
  0%, 42% { transform: scaleY(1); }
  46%, 50% { transform: scaleY(.1); }
  54%, 100% { transform: scaleY(1); }
}

물 두 겹과 양말·셔츠를 .ws__drum 한 그룹에 넣었으므로 회전은 선언 하나로 끝나고, 정지는 animation-play-state 로 애니메이션을 지우지 않고 잠시 멈춥니다. 고양이는 그룹 밖에서 2초 루프의 46% 지점에 한 번 눈을 깜빡이는데, 버튼을 누르면 드럼 계산값이 running 에서 paused 로, 패널 표시등은 1에서 0.25 로 꺼집니다.

02집 — 창문 불빛과 굴뚝 연기

줄무늬 지붕과 굴뚝을 가진 집이 스위치 한 번에 저녁으로 바뀌는, 부동산·홈서비스 온보딩 첫 화면용 부품입니다.

집 — 창문 불빛과 굴뚝 연기
새 창에서 열기

02 · 집 — 창문 불빛과 굴뚝 연기 — 측정 누적면적 22.172% · 움직인 프레임 22/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

repeating-linear-gradientanimation-delaytransition

낮과 밤은 겹침막 하나의 opacity

.hs__skynight {
  position: absolute; inset: 0; opacity: 0;
  background: linear-gradient(180deg, $night-top 0%, $night-bottom 100%);
  animation-name: hsCycle; animation-duration: $dur-loop;
  animation-timing-function: ease-in-out; animation-iteration-count: infinite;
}
.hs.is-night .hs__win {
  background: $stage-yellow;
  box-shadow: 0 0 12px rgba(255, 210, 63, .8);
}
@keyframes hsCycle {
  0%, 30% { opacity: 0; }
  52%, 78% { opacity: 1; }
  90%, 100% { opacity: 0; }
}

밤 하늘과 별·달을 .hs__skynight 겹침막 한 장에 담아 opacity 하나로 올리고 내리므로, 사람이 스위치를 누를 때는 transition 으로, 격자 미리보기에서는 같은 키프레임으로 움직입니다. 스위치를 끄면 창 유리가 rgb(255, 210, 63) 로 켜지며 12px 빛이 번지고, 연기 세 점은 660ms 간격의 animation-delay 로 시차를 두고 피어오르는데 지붕 줄무늬는 그림이 아니라 반복 그라디언트로 칠한 선입니다.

03다가오는 자동차와 노면

해 질 녘 도로로 정면으로 돌진해 오는 차를 몸체·헤드라이트·노면 표시로 짜맞춘, 자동차·배달 서비스 랜딩 히어로용 부품입니다.

다가오는 자동차와 노면
새 창에서 열기

03 · 다가오는 자동차와 노면 — 측정 누적면적 3.342% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

scalebox-shadowsteps(1, end)

노면 표시는 두 세트를 이어 아래로 흘린다

.ca__marks {
  position: absolute; left: 50%; top: -72px; width: 8px; height: 144px;
  margin-left: -4px;
  animation-name: caFlow; animation-duration: $duration;
  animation-timing-function: linear; animation-iteration-count: infinite;
}
// 간격은 margin-bottom — 무한 트랙에는 gap 을 쓰지 않는다
.ca__dash {
  display: block; width: 8px; height: 12px; margin-bottom: 12px;
  border-radius: $r-xs; background: rgba(255, 247, 230, .75);
}
@keyframes caFlow {
  from { transform: translateY(0); }
  to { transform: translateY(72px); }
}

차선 표시 여섯 개를 144px 트랙에 24px 간격으로 심고 72px(주기 세 칸)만큼 내리면 끝이 시작 상태와 정확히 겹쳐 이어지며, 다가옴은 차 그룹의 scale 왕복이 맡습니다. 방향지시등은 steps(1, end) 컷으로 깜빡이고 하이빔을 켜면 글로우 계산값이 matrix(1.7, 0, 0, 1.7, 0, 0) 까지 커지는데, 이 토글이 처음엔 보이지 않았던 까닭은 함정 섹션에서 이야기합니다.

04까마귀가 지나가는 워드마크

알록달록 그라디언트 글자 위를 검은 까마귀가 성큼성큼 걸어가는, 브랜드 워드마크·404 페이지용 부품입니다.

까마귀가 지나가는 워드마크
새 창에서 열기

04 · 까마귀가 지나가는 워드마크 — 측정 누적면적 6.609% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

background-clip: texttranslateXanimation-delay

글자는 배경을 잘라 내고 걸음은 다리 회전

.cr__word {
  font-weight: 900; font-size: 76px; line-height: 1; letter-spacing: 2px;
  background: linear-gradient(92deg, $grad-a 0%, $grad-b 48%, $grad-c 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.cr__leg {
  transform-origin: top center;
  animation-name: crStep; animation-duration: 250ms;
  animation-timing-function: linear; animation-iteration-count: infinite;
}
@keyframes crWalk {
  from { transform: translateX(0); }
  to { transform: translateX(400px); }
}

그라디언트는 background-clip: text 로 글자 모양만 남기고 까마귀는 몸통 타원·부리 삼각형·다리 막대 세 조각인데, 가로지름은 2초에 400px, 다리는 250ms 주기로 ±14도씩 엇갈려 돌아 걸음이 됩니다. 까마귀를 누르면 깃털 한 장이 rotate(140deg) 로 돌며 34px 내려와 떨어진 자리에 남고, 왼쪽 깃털 세 장은 300ms 간격 시차로 흔들립니다.

05온도조절기 풍경 창

둥근 스마트 온도조절기의 상단 창에 해가 뜨는 산과 호수를 넣고 모드 아이콘이 해의 높이와 온도를 함께 바꾸는, 스마트홈 제품 상세 화면용 부품입니다.

온도조절기 풍경 창
새 창에서 열기

05 · 온도조절기 풍경 창 — 측정 누적면적 0.536% · 움직인 프레임 19/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

clip-pathrotatetransition

모드 하나가 해·다이얼·온도를 같이 움직인다

.th[data-mode="snow"] .th__sun { transform: translateY(16px); opacity: .45; }
.th[data-mode="sun"] .th__sun { transform: translateY(-8px); opacity: 1; }
.th[data-mode="cloud"] .th__sun { transform: translateY(4px); opacity: .7; }
.th[data-mode="flame"] .th__sun { transform: translateY(0); opacity: .85; }
.th[data-mode="snow"] .th__dial { transform: rotate(0deg); }
.th[data-mode="sun"] .th__dial { transform: rotate(90deg); }
.th__sun { transition: transform $duration $easing, opacity $duration $easing; }

아이콘 버튼은 data-mode 속성 하나만 바꾸고 그림은 속성 선택자가 전부 맡으므로 JS 는 속성과 온도 숫자만 고칩니다. 해 모드에서 눈 모드를 누르면 해가 24px 내려가 흐려지고 다이얼은 90도에서 0도로 돌아가며 표시 온도는 27° 에서 18° 로 갈아끼워지는데, 산은 삼각형 두 개·호수 반사는 scaleX 왕복입니다.

06레트로 해와 원근 그리드

줄무늬 해와 야자수, 발밑으로 흐르는 원근 그리드로 짠 게임·음악 이벤트 랜딩용 씬입니다.

레트로 해와 원근 그리드
새 창에서 열기

06 · 레트로 해와 원근 그리드 — 측정 누적면적 3.71% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

perspectiverotateXtext-shadow

그리드는 눕혀 놓고 트랙째 흘린다

.rt__floor {
  position: absolute; left: 0; right: 0; bottom: 0; height: 62px;
  perspective: 240px; overflow: hidden;
}
.rt__grid {
  position: absolute; left: -60%; top: -100%; width: 220%; height: 200%;
  transform: rotateX(58deg); transform-origin: top center;
  background:
    repeating-linear-gradient(90deg, rgba($grid-pink, .8) 0 2px, transparent 2px 44px),
    repeating-linear-gradient(0deg, rgba($grid-pink, .55) 0 2px, transparent 2px 36px);
  animation-name: rtGridFlow; animation-duration: $duration;
  animation-timing-function: linear; animation-iteration-count: infinite;
}
@keyframes rtGridFlow {
  from { transform: rotateX(58deg) translateY(0); }
  to { transform: rotateX(58deg) translateY(36px); }
}

바닥에 perspective 를 두고 격자판을 rotateX(58deg) 로 눕히면 가로줄이 지평선으로 모이고, 흐름은 background-position 대신 격자판 자체를 세로 한 칸(36px) 밀어 transform 만으로 이어지게 했습니다. 해의 가로 줄은 아랫절반에 무대색 띠를 깐 겹침막이고 제목은 text-shadow 두 겹의 네온인데, 유성은 루프로 짧게 스치다가 버튼을 누르면 96px 대각선으로 한 번 관통합니다.

07물웅덩이 그라디언트 배경

물감이 번지듯 겹겹이 커지는 청록·분홍·보라 웅덩이가 어두운 무대 위에서 느리게 흔들리는, 명상·여행 서비스 배경용 부품입니다.

물웅덩이 그라디언트 배경
새 창에서 열기

07 · 물웅덩이 그라디언트 배경 — 측정 누적면적 5.185% · 움직인 프레임 22/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

radialGradienttransform-originmix-blend-mode

웅덩이 하나는 같은 색 타원 네 겹

<g class="pl__blob pl__blob--teal">
  <ellipse cx="96" cy="84" rx="64" ry="44" fill="url(#plTeal)" opacity=".34"/>
  <ellipse cx="99" cy="81" rx="52" ry="35" fill="url(#plTeal)" opacity=".5" transform="rotate(-8 99 81)"/>
  <ellipse cx="93" cy="86" rx="40" ry="26" fill="url(#plTeal)" opacity=".7" transform="rotate(7 93 86)"/>
  <ellipse cx="98" cy="82" rx="29" ry="18" fill="url(#plTeal)" opacity=".9" transform="rotate(-4 98 82)"/>
  <ellipse cx="96" cy="84" rx="18" ry="11" fill="#29d8c0"/>
</g>

한 웅덩이는 중심을 2~3px 씩 비틀어 놓은 타원 네 겹과 밝은 속살 하나라, 가장자리가 손으로 그린 듯 물결치는 이유는 겹마다 회전각과 중심이 다르기 때문입니다. SVG <g> 도 CSS 변형을 받으므로 transform-box: fill-box 를 주고 1초에 ±8도씩 흔들며 겹치는 부위는 mix-blend-mode: screen 으로 밝게 섞이는데, 클릭하면 청록이 translate(-62px, -58px) 로 가고 분홍이 그 반대로 와 자리가 맞바뀝니다.

08게임 회사풍 히어로 배경

보라 빛이 일렁이고 소용돌이 띠가 천천히 도는, 게임 회사 소개 히어로용 어두운 배경 부품입니다.

게임 회사풍 히어로 배경
새 창에서 열기

08 · 게임 회사풍 히어로 배경 — 측정 누적면적 13.677% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

repeating-conic-gradientanimation-directionfilter: blur

소용돌이는 방사형 줄무늬를 흐려서

.gh__swirl {
  position: absolute; right: -70px; top: -46px; width: 210px; height: 210px;
  border-radius: 50%;
  background: repeating-conic-gradient(rgba(138, 92, 214, .5) 0 14deg, rgba(138, 92, 214, 0) 14deg 42deg);
  -webkit-mask-image: radial-gradient(circle, rgba(0, 0, 0, 1) 0 52%, rgba(0, 0, 0, 0) 74%);
  mask-image: radial-gradient(circle, rgba(0, 0, 0, 1) 0 52%, rgba(0, 0, 0, 0) 74%);
  filter: blur(6px);
  animation-name: ghSwirl; animation-duration: $duration;
  animation-timing-function: ease-in-out; animation-iteration-count: infinite;
  animation-direction: alternate;
}
.gh.is-rev .gh__swirl { animation-direction: alternate-reverse; }

repeating-conic-gradient 로 부채꼴 줄무늬를 그리고 blur(6px) 로 녹인 뒤 방사형 마스크로 가장자리를 지우면 빙글 도는 소용돌이가 됩니다. 방향 뒤집기는 animation-direction 을 클래스 하나로 alternate-reverse 로 바꾸는 것이 전부라 계산값도 그 자리에서 바뀌며, 보라 블룸은 2초에 숨쉬고 입자 다섯 개는 시차를 두고 96px 씩 떠오릅니다.

09트렁크 가방 하우스

열어 놓은 오래된 트렁크 안에 거울·액자·반짝이 불빛·소파·램프가 들어 있는, 여행·리빙 브랜드 스토리 화면용 부품입니다.

트렁크 가방 하우스
새 창에서 열기

09 · 트렁크 가방 하우스 — 측정 누적면적 0.165% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

animation-delaybox-shadowtransition

반짝이는 여섯 개의 시차, 온기는 겹침막

.tk__bulb {
  position: absolute; width: 5px; height: 5px; border-radius: 50%;
  background: $stage-yellow;
  box-shadow: 0 0 6px rgba(255, 210, 63, .9);
  animation-name: tkTwinkle; animation-duration: $dur-loop;
  animation-timing-function: $ease-out; animation-iteration-count: infinite;
  animation-fill-mode: both;
}
@keyframes tkTwinkle {
  0%, 100% { opacity: .35; }
  18% { opacity: 1; }
  46% { opacity: .5; }
}
.tk__warm {
  position: absolute; inset: 0; opacity: 0; pointer-events: none;
  background: radial-gradient(circle at 72% 78%, rgba(255, 210, 63, .3) 0%, rgba(255, 210, 63, 0) 58%);
}

전구 여섯 개가 250ms 간격으로 순서대로 밝아져 불빛 줄이 살아 숨쉬고, 램프를 누르면 갓의 빛과 방 전체를 덮은 온기 겹침막의 opacity 가 함께 1로 올라갑니다. 겹침막은 램프보다 HTML 뒤에 있지만 화면 전체를 덮으므로 pointer-events: none 을 주지 않으면 클릭이 막히는데, 이 편을 만들며 실제로 램프를 누를 수 없어서 붙인 줄입니다.

css 이미지 애니메이션 효과를 도형만으로 내려면 무엇부터 정해야 하나?

css 애니메이션 예제를 사물로 만들 때 첫 결정은 무엇이 도는가입니다. 사물 일부(드럼·다리)만 움직일지, 사물 전체(차의 다가옴)가 움직일지, 배경(노면·그리드)이 흐를지를 먼저 정하면 마크업이 결정되는데, 아홉 개 중 다섯은 사물 일부의 회전·확대이고 넷은 상태 바꾸기라서 애니메이션과 transition 을 나눠 쓸 수 있었습니다. 두 번째 결정은 무대색이라, 잉크 무대의 크림 몸체(01)에서는 측정 강도가 117.7 까지 나왔지만 같은 도형을 밝은 무대에 두면 그보다 줄어드므로 피사체와 무대는 세트로 고릅니다. 사물을 어디서부터 그릴지 모를 때는 이 편처럼 가장 큰 덩어리(몸체·지붕·차체)부터 놓고 구멍(창·도어·전조등)을 뚫는 순서가 가장 빠릅니다.

어디서 깨지는가 — 애니메이션이 transition 을 이긴다

03 하이빔은 처음에 동작하지 않았습니다. 글로우에 맥동 애니메이션(2초 왕복 scale .92↔1.08)을 걸어 두고 버튼에는 scale(1.7) 전환을 걸었더니 눌러도 계산값이 맥동 중간값인 matrix(0.96283) 그대로였는데, CSS 명세상 애니메이션의 값이 transition 보다 항상 우선이라 둘이 같은 속성을 노리면 전환이 아무리 빨라도 보이지 않기 때문입니다. 고친 방법은 상태가 켜진 동안 애니메이션을 끄는 것입니다.

.ca.is-beam .ca__glow {
  animation-name: none;
  transform: scale(1.7); opacity: 1;
}

animation-name: none 한 줄로 맥동이 물러나고 scale(1.7) 전환이 드러나며 다시 끄면 맥동이 이어집니다. 아홉 개 파일의 압축 비밀번호는 <span class="pw-inline" id="pw">5ak22r6m</span> 이고, 풀면 바닐라판과 React 판이 함께 들어 있습니다.

변형 세 가지와 접근성

이름 바꾸는 값 느낌
duration $dur-loop 2s → 4s 드럼·연기·그리드가 절반 속도로 늘어져 차분한 전시 장면이 된다
easing $ease-out → $ease-pop 까마귀 걸음과 유성에 한 번의 반동이 붙어 씬이 통튀어 오른다
color 무대 ink → paper 같은 도형이 밤 전시장에서 화이트 갤러리 무대로 옮겨 분위기가 갈린다

셋 다 각 항목의 style.scss 맨 위 변수 세 줄만 고치면 됩니다. prefers-reduced-motion 에서는 아홉 개 모두 회전·흐름·반짝임을 끄고 그 부품이 가장 잘 읽히는 정지 상태를 남기는데, 드럼은 멈춘 물 위 양말·집은 낮 풍경·까마귀는 글자 위에 선 자세입니다. 정지 상태에서도 시작·정지·모드·램프 버튼은 그대로 누를 수 있습니다.

FAQ

css 이미지 애니메이션 효과를 사물에 붙일 때 그림 파일은 꼭 필요한가요?

필요하지 않습니다. 이 편의 아홉 개는 전부 둥근 모서리와 clip-path·그라디언트 조각이라 이미지가 0개고, 받는 zip 도 HTML 과 SCSS(또는 React 판 두 파일)만 들어 있습니다. 그림이 없으면 고치기도 쉽고 색만 바꿔 다른 사물로 변형됩니다.

세탁기 드럼처럼 계속 도는 사물은 배터리를 많이 쓰나요?

움직이는 것은 transform 과 opacity 로 제한했으므로 레이아웃을 다시 계산하지 않고 GPU 가 그립니다. 다만 화면에 여러 개를 한꺼번에 넣을 때는 animation-play-state 로 보이지 않는 사물을 멈추는 편이 안전한데, 이 데모의 시작·정지 버튼이 정확히 그 역할입니다.

도형으로 그린 사물이 내 화면에서 찌그러져 보이면 무엇을 고치나요?

거의 항상 무대 크기와 사물 크기의 조합입니다. 데모는 480×300 기준으로, 320px 폭에서도 넘치지 않게 좁은 화면 규칙을 두었는데, 사물을 키울 때는 이 규칙부터 다시 맞춰야 합니다. 세로로 넘치면 격자 칸에 스크롤바가 생겨 씬이 잘립니다.

압축 비밀번호를 입력하세요

비밀번호는 이 글 본문 안에 있습니다. 읽다 보면 나옵니다.