손그림 디자인 랜딩 UI 키트, 크레용 섹션 9개
손그림 디자인은 굵고 삐뚤빼뚤한 크레용 선으로 테두리를 그리고, 그 선만 SVG 필터로 살짝 흔들어 종이 위에 손으로 그은 낙서처럼 보이게 만드는 스타일입니다. 동네 미술학원이나 어린이 브랜드 사이트에서 본 그 느낌인데 이름을 몰라 검색을 못 했던 바로 그 화면입니다.
핀터레스트에 캡처로만 저장해 두던 이 화면을, 실제로 만든 원페이지로 아래에 그대로 올렸습니다. 내비게이션부터 푸터까지 스크롤하면서 전체 인상을 먼저 확인해 보세요.
이번엔 그 화면을 뜯어서 낱개 부품 아홉 종으로 다시 배열했습니다. 처음 랜딩을 열었을 때 시선이 흐르는 순서 — 둘러보기, 기능 확인, 가격, 신뢰, 행동 유도, 가입 — 를 그대로 따릅니다. 손으로 그린 줄 알았는데 사실 CSS였던 부분은 셋(낙서 히어로·이중선 카드·지그재그 푸터)이 전부 같은 원리로 돌아간다는 것입니다. 테두리나 윗변을 그리는 도형에만 흔들림 필터 또는 들쭉날쭉한 절단선을 걸고, 글자를 담은 요소는 건드리지 않습니다.
자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip
- 01 크레용 낙서 히어로
- 02 손그림 동그라미 내비
- 03 삐뚤빼뚤 스티커 카드 격자
- 04 손그림 체크 목록
- 05 별표 동그라미 요금제
- 06 크레용 말풍선 후기
- 07 크레용 해칭 CTA 밴드
- 08 가위질 지그재그 푸터
- 09 이중선 크레용 버튼·인풋
이 키트의 색은 일곱 개로 끝납니다. 글자는 항상 잉크색 하나로 고정하는 것이 읽히는 손그림의 조건입니다.
| 역할 | 색 | 쓰는 곳 |
|---|---|---|
| 종이 | #fff8ef |
페이지 바탕 전체 |
| 잉크 | #33261c |
모든 글자 (대비 12.1~13.9:1) |
| 레드 크레용 | #ff5a5f |
손그림 선·강조 테두리 |
| 옐로 크레용 | #ffcd3c |
버튼·별·밑줄 |
| 블루 크레용 | #4fa3e3 |
이중선·포커스 링 |
| 그린 크레용 | #6dbe6d |
체크·아바타 |
| 퍼플 크레용 | #a685e2 |
CTA 배경 틴트 |
01크레용 낙서 히어로
카드 테두리는 글자와 분리된 SVG 사각형 레이어이고, 그 레이어에만 feTurbulence 흔들림 필터를 걸어 굵은 점선이 손으로 그은 것처럼 삐뚤거립니다. 제목 아래 노란 밑줄은 stroke-dashoffset으로 그려졌다 지워지길 반복합니다.
<svg width="0" height="0" style="position:absolute">
<filter id="rough" x="-30%" y="-30%" width="160%" height="160%">
<feTurbulence type="fractalNoise" baseFrequency="0.045" numOctaves="2" seed="4" result="n"/>
<feDisplacementMap in="SourceGraphic" in2="n" scale="7"
xChannelSelector="R" yChannelSelector="G"/>
</filter>
</svg>
<svg class="frame" viewBox="0 0 300 190" preserveAspectRatio="none">
<rect x="6" y="6" width="288" height="178" rx="20"
stroke="#33261c" stroke-width="5" stroke-dasharray="16 11"
fill="none" filter="url(#rough)" />
</svg>
02손그림 동그라미 내비
활성 탭 글자 둘레를 빨간 크레용 동그라미가 감싸는데, 완벽한 원이 아니라 한쪽 끝이 다른 쪽을 살짝 지나치는 이중 루프라 방금 그린 것처럼 보입니다. stroke-dasharray를 다 그렸다가 반대 방향으로 지웁니다.
<li class="relative px-2 py-1">
<span class="relative z-10 text-xs font-semibold">홈</span>
<svg class="loop" viewBox="0 0 56 30">
<path fill="none" stroke="#ff5a5f" stroke-width="3.5"
stroke-linecap="round" stroke-linejoin="round"
stroke-dasharray="110"
d="M28 4 C 13 2, 4 11, 7 17 C 9 25, 20 28, 29 26
C 41 24, 50 17, 47 10 C 45 4, 33 2, 25 5" />
</svg>
</li>
03삐뚤빼뚤 스티커 카드 격자
카드마다 빨강·파랑 두 선을 1~2px 어긋나게 겹쳐 크레용으로 두 번 그은 흔적을 냅니다. 카드 네 장은 시작 시각을 140ms씩 어긋내 순서대로 살짝 기웁니다.
<svg class="frame" viewBox="0 0 100 78" preserveAspectRatio="none">
<rect x="5" y="5" width="90" height="68" rx="12"
fill="none" stroke="#ff5a5f" stroke-width="2.4" />
<rect x="3" y="3" width="90" height="68" rx="12"
fill="none" stroke="#4fa3e3" stroke-width="2.4" opacity=".8" />
</svg>
04손그림 체크 목록
체크 표시는 아이콘 폰트가 아니라 획 하나짜리 SVG 경로가 왼쪽부터 오른쪽까지 그려지는 애니메이션입니다. 행마다 색과 시작 시각이 달라 체크가 제 박자로 완성됩니다.
<svg class="check" viewBox="0 0 20 16">
<path fill="none" stroke="#ff5a5f" stroke-width="3"
stroke-linecap="round" stroke-linejoin="round"
stroke-dasharray="26"
d="M2 9 C 3 8, 4 10, 7 13 C 10 10, 14 6, 18 2" />
</svg>
<style>
.check path { animation: checkDraw 2s ease-out infinite; }
@keyframes checkDraw {
0% { stroke-dashoffset: 26; opacity: 0; }
45% { stroke-dashoffset: 0; opacity: 1; }
100% { stroke-dashoffset: -26; opacity: 0; }
}
</style>
05별표 동그라미 요금제
세 요금제 카드는 저마다 다른 크레용 톤이고, 추천 플랜의 가격 숫자만 손그림 동그라미가 스스로 둘러 그려지며 옆에 작은 별 두 개가 다른 박자로 반짝입니다. 표 없이 색과 동그라미만으로 눈이 갑니다.
.ring-path {
fill: none;
stroke: #ff5a5f;
stroke-width: 3.2;
stroke-dasharray: 190;
animation: ringDraw 2s ease-out infinite;
}
@keyframes ringDraw {
0% { stroke-dashoffset: 190; }
50% { stroke-dashoffset: 0; }
100% { stroke-dashoffset: -190; }
}
06크레용 말풍선 후기
말풍선은 반듯한 사각형이 아니라 윤곽선이 울퉁불퉁한 SVG 패스이고, 꼬리도 매끈한 삼각형 대신 꺾인 선 두 개로 그립니다. 별점은 다섯 개 폭을 100·100·100·80·40%로 다르게 채워 진짜 후기처럼 보이게 했습니다.
<svg class="frame" viewBox="0 0 260 110" preserveAspectRatio="none">
<path fill="#fff8ef" stroke="#33261c" stroke-width="3" stroke-linejoin="round"
d="M18 10 L242 10 C250 10 252 18 252 26 L252 78 C252 88 248 96 238 96
L48 96 L30 110 L34 94 L18 92 C10 90 8 82 8 74
L8 26 C8 16 10 10 18 10 Z" />
</svg>
07크레용 해칭 CTA 밴드
밴드 배경은 이미지 없이 repeating-linear-gradient 한 줄로 그린 빗금 해칭이고, 그 위 버튼은 빨간 점선 테두리가 계속 행진하듯 다시 그려집니다. 색칠북 한 페이지에 놓인 버튼 같습니다.
.band {
background:
repeating-linear-gradient(45deg, rgba(51,38,28,.08) 0 2px, transparent 2px 9px),
#efe6fb;
}
.btn-rect {
fill: none; stroke: #ff5a5f; stroke-width: 3;
stroke-dasharray: 14 8;
animation: march 2s linear infinite;
}
@keyframes march { to { stroke-dashoffset: -440; } }
08가위질 지그재그 푸터
푸터 윗변은 조각마다 요소를 하나씩 두지 않고 clip-path: polygon() 하나로 높낮이가 들쭉날쭉한 톱니를 그려 아이가 가위로 대충 오린 것처럼 보이게 합니다. 균일한 지그재그가 아니라 점마다 높이가 다른 게 핵심입니다.
.zigzag {
height: 14px;
background: #33261c;
clip-path: polygon(
0% 100%, 0% 30%, 6% 85%, 12% 15%, 18% 90%, 24% 20%,
30% 88%, 36% 12%, 42% 92%, 48% 18%, 54% 85%, 60% 22%,
66% 90%, 72% 15%, 78% 88%, 84% 20%, 90% 92%, 96% 14%,
100% 30%, 100% 100%
);
}
09이중선 크레용 버튼·인풋
버튼은 빨강·파랑 두 선이 살짝 어긋났다 돌아오길 반복해 손맛을 내고, 입력창은 손으로 두른 파란 동그라미가 계속 번지듯 커졌다 사라지길 반복합니다. 키보드로 초점을 옮기면 버튼과 입력창 둘 다 별도의 :focus-visible 윤곽선이 뜹니다.
.btn-rect-a { stroke: #ff5a5f; animation: shiftA 2s infinite; }
.btn-rect-b { stroke: #4fa3e3; opacity: .85; animation: shiftB 2s infinite; }
@keyframes shiftA { 50% { transform: translate(-2px, 1px); } }
@keyframes shiftB { 50% { transform: translate(2px, -1px); } }
.ring-rect { animation: bloom 2s infinite; }
@keyframes bloom {
0%, 100% { opacity: 0; transform: scale(.9); }
50% { opacity: 1; transform: scale(1); }
}
tailwind.config 커스텀
크레용 일곱 색과 반경 세 종을 이 한 곳에 적어 두면 원페이지와 부품 아홉 개가 전부 같은 규칙을 따라갑니다. 흔들림 필터의 id는 부품마다 rough1·rough2처럼 번호를 따로 붙여 겹치지 않게 하고, 전체를 모은 원페이지에서만 rough 하나로 합칩니다.
theme: {
extend: {
colors: {
paper: "#fff8ef", ink: "#33261c", red: "#ff5a5f",
yellow: "#ffcd3c", blue: "#4fa3e3", green: "#6dbe6d", purple: "#a685e2",
},
borderRadius: { crayon: "20px", control: "12px", pill: "999px" },
spacing: { gutter: "16px" },
},
},
바이브코딩 프롬프트
config를 프로젝트에 넣은 뒤 Claude Code·Cursor에 건네는 말은 SVG 필터를 어디에 걸고 어디에 걸지 않는지가 핵심입니다. 지시문 전문은 zip의 prompt.md에 담겨 있습니다.
배경은 paper(#fff8ef) 하나로 통일한다. 테두리가 있는 박스마다 흔들리는 손그림
테두리(SVG feTurbulence + feDisplacementMap)를 별도 레이어로 건다 — 글자를
감싸는 요소 전체에는 절대 걸지 않는다. 카드 모서리는 rounded-crayon 또는
rounded-pill로 통일한다. 이중선을 쓸 땐 빨강과 파랑을 1~2px 어긋나게 겹친다.
이 지시문을 page/index.html로 실제로 구현해 1280px 화면 전체를 찍은 것이 아래 그림입니다.

어디서 깨지는가 — 함정
가장 먼저 겪은 함정은 흔들림 필터를 어디에 거느냐입니다. 처음엔 카드 전체(테두리 더하기 글자)를 통째로 filter: url(#rough)로 감쌌더니 feDisplacementMap이 픽셀을 전부 같은 규칙으로 밀어내는 바람에 제목 글자까지 삐뚤빼뚤 번져 읽기 어려워졌습니다. 테두리를 그리는 SVG rect·path만 별도 레이어로 떼어 놓고 그 레이어에만 필터를 걸자 글자는 또렷하게 남고 테두리만 흔들렸습니다.
두 번째는 실측으로 잡은 숫자입니다. 푸터의 별 두 개 반짝임만으로 움직임을 재니 누적면적이 0.07%로 설정 하한(0.08%)에 못 미쳐 정지 화면과 구분이 안 됐습니다. 별 크기를 14px에서 20px로, 확대 범위를 0.7~1.2배에서 0.5~1.7배로 넓히자 0.35%로 올라가 통과했습니다. 세 번째는 활성 탭을 두르는 동그라미의 크기였습니다. 뷰박스를 92×50으로 처음 그렸더니 렌더된 화면에서 원이 옆 탭 글자까지 침범했고, 56×30으로 줄이고 나서야 "홈" 글자만 정확히 감쌌습니다. 이 세 가지를 다 잡은 완성본을, 이 비밀번호 r6qyfm69이 걸린 zip을 받아 그대로 열어 확인할 수 있습니다.
아홉 개 데모 전부 MDN prefers-reduced-motion 문서가 정의한 미디어 쿼리를 감지하면 선이 그려지는 애니메이션과 카드가 기우는 움직임을 멈추고, 각 요소를 다 그려진 상태(체크는 완성된 모양, 동그라미는 닫힌 원)로 고정합니다.
접근성
손그림 스타일의 가장 흔한 실패는 흔들림 필터를 글자에까지 거는 것입니다. feDisplacementMap은 소스 그래픽의 모든 픽셀을 노이즈 맵 값만큼 밀어내는데, 이건 글자 획도 예외가 아니라서 작은 크기에서는 자모가 뭉개져 읽기 어려워집니다. 이 키트는 그래서 필터를 항상 테두리 전용 SVG 레이어에만 걸고 글자 요소는 건드리지 않습니다. 글자색은 전부 짙은 잉크(#33261c)로 고정해 종이 바탕 위에서 13.9:1, 카드에 쓰는 가장 어두운 틴트(퍼플 틴트) 위에서도 12.1:1로 WCAG 2.1 최소 대비 기준 4.5:1을 넉넉히 넘습니다. 빨강·파랑 강조선은 장식용 테두리라 텍스트 대비 기준 대상이 아니지만, 버튼·입력창의 키보드 초점은 색선에 기대지 않고 :focus-visible 아웃라인을 잉크색으로 별도 그렸습니다.
크레용 말고 다른 밝은 톤 홈페이지 유행이 궁금하면 파스텔 캔디 랜딩도 함께 보시고, 디자인 트렌드 카테고리 전체와 이 블로그 소개는 소개 페이지에 정리해 뒀습니다.
FAQ
손그림 디자인이랑 그냥 스케치 폰트 쓰는 건 뭐가 달라요?
스케치 폰트는 글자 모양 자체를 손글씨처럼 바꾸는 것이고, 이 키트는 글자는 반듯한 서체 그대로 두고 테두리·밑줄·체크 같은 장식 선만 SVG 필터로 흔듭니다. 글자를 흔들면 가독성이 떨어지지만 테두리만 흔들면 귀여움은 살고 읽기는 그대로입니다.
어두운 톤 브랜드에도 이 스타일을 쓸 수 있나요?
쓸 수 있지만 paper(#fff8ef) 대신 짙은 바탕을 쓰려면 잉크 글자색도 밝은색으로 뒤집어야 대비가 유지됩니다. 크레용 선 색 일곱 개 중 빨강·노랑처럼 채도가 높은 색은 어두운 바탕에서도 그대로 써도 되지만, 카드 틴트는 어두운 버전으로 다시 잡아야 합니다.
feTurbulence 필터가 느리진 않나요?
이 키트의 필터는 테두리를 그리는 작은 SVG 레이어 하나에만 걸리고 값이 고정돼 있어(애니메이션 자체는 stroke-dashoffset·transform이 담당) 매 프레임 다시 계산하지 않습니다. 카드 전체나 페이지 전체에 필터를 걸면 느려지니, 항상 테두리 레이어처럼 작은 요소에만 국한해서 씁니다.