04손그림 체크 목록
행마다 크레용으로 쓱쓱 그은 체크 표시가 획 하나짜리 SVG 선으로 왼쪽부터 오른쪽까지 그려지고, 행마다 시작 시각을 어긋내면 체크가 순서대로 완성됩니다. 반듯한 아이콘 폰트보다 느낌이 훨씬 손맛 납니다.
쓰임기능 목록, 준비물 체크리스트
stroke-dashoffset 체크어긋난 시작 시각radius 12

<main class="stage">
<ul class="listcrayon">
<li class="listcrayon__row listcrayon__row--1">
<svg class="listcrayon__check" viewBox="0 0 20 16" aria-hidden="true">
<path class="listcrayon__check-path" d="M2 9 C 3 8, 4 10, 7 13 C 10 10, 14 6, 18 2" />
</svg>
<span class="listcrayon__text">드래그로 배치</span>
</li>
<li class="listcrayon__row listcrayon__row--2">
<svg class="listcrayon__check" viewBox="0 0 20 16" aria-hidden="true">
<path class="listcrayon__check-path" d="M2 9 C 3 8, 4 10, 7 13 C 10 10, 14 6, 18 2" />
</svg>
<span class="listcrayon__text">색상 골라 칠하기</span>
</li>
<li class="listcrayon__row listcrayon__row--3">
<svg class="listcrayon__check" viewBox="0 0 20 16" aria-hidden="true">
<path class="listcrayon__check-path" d="M2 9 C 3 8, 4 10, 7 13 C 10 10, 14 6, 18 2" />
</svg>
<span class="listcrayon__text">손그림 아이콘 고르기</span>
</li>
<li class="listcrayon__row listcrayon__row--4">
<svg class="listcrayon__check" viewBox="0 0 20 16" aria-hidden="true">
<path class="listcrayon__check-path" d="M2 9 C 3 8, 4 10, 7 13 C 10 10, 14 6, 18 2" />
</svg>
<span class="listcrayon__text">바로 공유하기</span>
</li>
</ul>
</main>@use "../../../../site/static/demo-tokens" as *;
$duration: $dur-loop; // 체크가 한 번 그려지는 주기
$easing: $ease-out; // 선이 그려지는 곡선
$color: $stage-ink; // 글자 색 기본값(토큰) — 아래 크레용 잉크로 덮는다
$crayon-paper: #fff8ef;
$crayon-ink: #33261c;
$crayon-red: #dbb6b7;
$crayon-yellow: #d1c5a2;
$crayon-blue: #9cb8ce;
$crayon-green: #6dbe6d;
$crayon-purple: #cbbfe0;
@include stage($crayon-paper);
.listcrayon {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: $sp-2;
width: clamp(220px, 80vw, 300px);
}
.listcrayon__row {
display: flex;
align-items: center;
gap: $sp-3;
border-radius: $r-pill;
background: $stage-paper;
border: 2px solid rgba($crayon-ink, .16);
padding: $sp-2 $sp-4;
}
.listcrayon__check {
flex-shrink: 0;
width: 24px;
height: 20px;
overflow: visible;
}
.listcrayon__check-path {
fill: none;
stroke-width: 3;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 26;
animation: checkDraw $duration $easing infinite;
}
.listcrayon__row--1 .listcrayon__check-path { stroke: $crayon-red; animation-delay: 0ms; }
.listcrayon__row--2 .listcrayon__check-path { stroke: $crayon-blue; animation-delay: 160ms; }
.listcrayon__row--3 .listcrayon__check-path { stroke: $crayon-green; animation-delay: 320ms; }
.listcrayon__row--4 .listcrayon__check-path { stroke: $crayon-purple; animation-delay: 480ms; }
.listcrayon__text {
color: $crayon-ink;
font-weight: 600;
font-size: clamp(11px, 2.8vw, 13px);
}
// 데모: 체크 표시가 왼쪽부터 오른쪽까지 한 획으로 그려졌다 지워지길 반복하며, 행마다 시작이 어긋난다
@keyframes checkDraw {
0% { stroke-dashoffset: 26; opacity: 0; }
6% { opacity: 1; }
45% { stroke-dashoffset: 0; opacity: 1; }
80% { stroke-dashoffset: 0; opacity: 1; }
100% { stroke-dashoffset: -26; opacity: 0; }
}
@media (max-width: 340px), (max-height: 220px) {
.listcrayon { gap: $sp-1; }
.listcrayon__row { padding: $sp-1 $sp-3; gap: $sp-2; }
}
@media (prefers-reduced-motion: reduce) {
.listcrayon__check-path {
animation: none !important;
stroke-dashoffset: 0;
opacity: 1;
}
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #fff8ef;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.listcrayon {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 8px;
width: clamp(220px, 80vw, 300px);
}
.listcrayon__row {
display: flex;
align-items: center;
gap: 12px;
border-radius: 999px;
background: #ffffff;
border: 2px solid rgba(51, 38, 28, 0.16);
padding: 8px 16px;
}
.listcrayon__check {
flex-shrink: 0;
width: 24px;
height: 20px;
overflow: visible;
}
.listcrayon__check-path {
fill: none;
stroke-width: 3;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 26;
animation: checkDraw 2s ease-out infinite;
}
.listcrayon__row--1 .listcrayon__check-path {
stroke: #dbb6b7;
animation-delay: 0ms;
}
.listcrayon__row--2 .listcrayon__check-path {
stroke: #9cb8ce;
animation-delay: 160ms;
}
.listcrayon__row--3 .listcrayon__check-path {
stroke: #6dbe6d;
animation-delay: 320ms;
}
.listcrayon__row--4 .listcrayon__check-path {
stroke: #cbbfe0;
animation-delay: 480ms;
}
.listcrayon__text {
color: #33261c;
font-weight: 600;
font-size: clamp(11px, 2.8vw, 13px);
}
@keyframes checkDraw {
0% {
stroke-dashoffset: 26;
opacity: 0;
}
6% {
opacity: 1;
}
45% {
stroke-dashoffset: 0;
opacity: 1;
}
80% {
stroke-dashoffset: 0;
opacity: 1;
}
100% {
stroke-dashoffset: -26;
opacity: 0;
}
}
@media (max-width: 340px), (max-height: 220px) {
.listcrayon {
gap: 4px;
}
.listcrayon__row {
padding: 4px 12px;
gap: 8px;
}
}
@media (prefers-reduced-motion: reduce) {
.listcrayon__check-path {
animation: none !important;
stroke-dashoffset: 0;
opacity: 1;
}
}import type { CSSProperties } from "react";
import styles from "./FeatureListCrayon.module.scss";
export type FeatureListCrayonProps = {
items?: string[];
duration?: number;
easing?: string;
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
const DEFAULT_ITEMS = ["드래그로 배치", "색상 골라 칠하기", "손그림 아이콘 고르기", "바로 공유하기"];
const COLORS = ["#ff5a5f", "#4fa3e3", "#6dbe6d", "#a685e2"];
export default function FeatureListCrayon({
items = DEFAULT_ITEMS,
duration = 2000,
easing = "ease-out",
color = "#ff5a5f",
}: FeatureListCrayonProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
return (
<ul className={styles.list} style={vars}>
{items.map((text, i) => (
<li key={text} className={styles.row}>
<svg className={styles.check} viewBox="0 0 20 16" aria-hidden="true">
<path
className={styles.checkPath}
style={{ stroke: COLORS[i % COLORS.length], animationDelay: `${i * 160}ms` }}
d="M2 9 C 3 8, 4 10, 7 13 C 10 10, 14 6, 18 2"
/>
</svg>
<span className={styles.text}>{text}</span>
</li>
))}
</ul>
);
}04 손그림 체크 목록 — 측정 누적면적 0.372% · 움직인 프레임 18/23GODRICH 원작 · zip 에 SCSS·React 포함 · 손그림 디자인 랜딩 UI 키트, 크레용 섹션 9개
이 데모가 속한 글
손그림 디자인 랜딩 UI 키트, 크레용 섹션 9개손그림 디자인은 굵고 삐뚤빼뚤한 크레용 선으로 테두리를 그리고, 그 선만 SVG 필터로 살짝 흔들어 종이 위에 손으로 그은 낙서처럼 보이게 만드는 스타일입니다. 동네 미술학원이나 어린이 브랜드 사이트에서 본 그 느낌 이 글의 데모 전부 보기


