Flow
원본: projects/skill-lens/design/components/Flow/README.md
상태: Experimental, 접근성 △(데모), 다크 ✓, 코드 ✗
단계 이동 데모: 옆으로 24px 밀며 들어옴(흐림 없음, 360ms), 진행 점 렌즈가 같은 시간 동안 미끄러짐, 내용은 아래에서 12px 떠오름
다섯 단계가 실제로 넘어가는 데모입니다. 단계 이동 규칙을 한 장에서 보여 줍니다.
쓰는 곳
부품 보기와 검토. 제품 화면에는 이동 규칙만 가져갑니다.
구성(화면이 넘겨줄 것)
각 단계의 내용.
규칙
- 단계 이동은 옆으로: 다음은 오른쪽 24px에서, 이전은 왼쪽 24px에서 밀며 들어옵니다. 흐림 없음, 360ms(폰 300),
ease-scene(8판 .pg-fw, .pg-bk에서 흐림만 뺌). - 진행 점의 현재 위치는 작은 렌즈이고 같은 시간 동안 다음 점으로 미끄러집니다.
- 새 화면의 내용은 아래에서 12px 떠오르며 시차를 두고 등장합니다.
접근성
- 움직임 줄이기에서는 전환 없이 바로 바뀝니다.
견본 코드
AI 읽기 도구는 위 견본(iframe)을 그리지 못하므로 같은 견본의 HTML을 글로 둔다. 스타일은 bundle.css, 값은 tokens.css.
<!-- @dsCard group="Layout" height=720 subtitle="단계 이동 데모: 옆으로 24px 밀며 들어옴(흐림 없음, 360ms), 진행 점 렌즈가 같은 시간 동안 미끄러짐, 내용은 아래에서 12px 떠오름" -->
<style>body{margin:0;padding:var(--space-4);background:var(--canvas)}.phone{position:relative;width:390px;height:680px;border-radius:36px;overflow:hidden;background:var(--surface-sunken);box-shadow:var(--shadow-sheet)}.head{padding:20px 20px 0}.body{flex:1;padding:4px 20px 0;display:flex;flex-direction:column;gap:8px;overflow:hidden}.sl-cta{margin-top:auto}</style>
<div class="sl phone sl-stage" id="stage">
<div class="sl-page" data-i="0"><div class="head"><div class="sl-steps"><div class="sl-steps__label"><span>1/5</span><span>회사, 목적, 목표</span><span style="color:var(--ink-subtle)">(1/3)</span></div><div class="sl-steps__track"><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__fill" style="width:calc((100% - 10px) * 0)"></i><i class="sl-steps__glide" style="left:calc(5px + (100% - 10px) * 0)"></i></div></div>
<div class="sl-top"><h1 class="sl-top__title"><span class="sl-accent">가온에듀</span>가 맞나요?</h1><p class="sl-top__desc">공개 자료에서 찾았어요. 다르면 아래에서 고칠 수 있어요.</p></div></div>
<div class="body sl-stagger"><div class="sl-card"><div style="font:800 20px/28px var(--font-sans);letter-spacing:-.5px">가온에듀 <span style="font:500 13px/20px var(--font-sans);color:var(--ink-muted)">교육 서비스업, 코스피</span></div><div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:12px;font:400 13px/20px var(--font-sans);color:var(--ink-muted)"><div>업종<br><b style="color:var(--ink)">교육 서비스업</b></div><div>지역<br><b style="color:var(--ink)">경기 성남</b></div><div>규모<br><b style="color:var(--ink)">약 1,270명</b></div><div>최대인원<br><b style="color:var(--ink)">1,500명</b></div></div></div><button class="sl-btn sl-btn--link" style="align-self:flex-start">정보가 달라요</button></div>
<div class="sl-cta"><button class="sl-btn sl-btn--primary" data-next>맞아요 <span class="sl-btn__arrow">→</span></button></div></div>
<div class="sl-page" data-i="1" hidden><div class="head"><div class="sl-steps"><div class="sl-steps__label"><span>1/5</span><span>회사, 목적, 목표</span><span style="color:var(--ink-subtle)">(2/3)</span></div><div class="sl-steps__track"><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__fill" style="width:calc((100% - 10px) * 0)"></i><i class="sl-steps__glide" style="left:calc(5px + (100% - 10px) * 0)"></i></div></div>
<div class="sl-top"><h1 class="sl-top__title">이번 진단으로<br><span class="sl-accent">어떤 변화</span>를 만들고 싶나요?</h1><p class="sl-top__desc">목적을 고르면 진단 스킬 초안을 만들어요.</p></div></div>
<div class="body sl-stagger" role="radiogroup"><button class="sl-option" role="radio" aria-checked="true"><span class="sl-tile"><svg class="sl-ico" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/></svg></span><span><span class="sl-option__title">AI 업무 전환</span><span class="sl-option__desc">AI로 일하는 방식이 바뀌는 조직</span></span></button><button class="sl-option" role="radio" aria-checked="false"><span class="sl-tile sl-tile--neutral"><svg class="sl-ico" viewBox="0 0 24 24" aria-hidden="true"><rect width="7" height="7" x="3" y="3" rx="1"/><rect width="7" height="7" x="14" y="3" rx="1"/><rect width="7" height="7" x="14" y="14" rx="1"/><rect width="7" height="7" x="3" y="14" rx="1"/></svg></span><span><span class="sl-option__title">전직원 스킬 진단</span></span></button><button class="sl-option" role="radio" aria-checked="false"><span class="sl-tile sl-tile--green"><svg class="sl-ico" viewBox="0 0 24 24" aria-hidden="true"><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"/><path d="M20 3v4"/><path d="M22 5h-4"/></svg></span><span><span class="sl-option__title">신사업 준비</span></span></button><div class="sl-summary"><p class="sl-summary__title">AI 업무 전환을 준비하면</p><ul class="sl-summary__list"><li>스킬 166개 중 43개를 진단해요</li><li>1인당 진단 스킬 12~24개</li></ul></div></div>
<div class="sl-cta"><div class="sl-cta__row"><button class="sl-btn sl-btn--secondary" data-prev>이전</button><button class="sl-btn sl-btn--primary" data-next>다음 <span class="sl-btn__arrow">→</span></button></div></div></div>
<div class="sl-page" data-i="2" hidden><div class="head"><div class="sl-steps"><div class="sl-steps__label"><span>2/5</span><span>직무</span></div><div class="sl-steps__track"><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__fill" style="width:calc((100% - 10px) * 0.25)"></i><i class="sl-steps__glide" style="left:calc(5px + (100% - 10px) * 0.25)"></i></div></div>
<div class="sl-top"><h1 class="sl-top__title">업종에 맞는 <span class="sl-accent">직무 46개</span>를<br>추천했어요</h1><p class="sl-top__desc">41개는 바로 쓸 수 있고, 5개만 확인하면 돼요.</p></div></div>
<div class="body"><div class="sl-stats sl-stagger"><div class="sl-stat"><span class="sl-stat__value" data-count="46">0</span><span class="sl-stat__label">추천</span></div><div class="sl-stat sl-stat--accent"><span class="sl-stat__value" data-count="41">0</span><span class="sl-stat__label">바로 사용</span></div><div class="sl-stat sl-stat--attention"><span class="sl-stat__value" data-count="5">0</span><span class="sl-stat__label">확인 필요</span></div></div><div class="sl-stagger" style="display:flex;flex-direction:column;gap:8px"><div class="sl-row"><span class="sl-tile sl-tile--sm sl-tile--orange"><svg class="sl-ico sl-ico--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z"/><path d="M22 10v6"/><path d="M6 12.5V16a6 3 0 0 0 12 0v-3.5"/></svg></span><span class="sl-row__main">전문도 개발</span><span class="sl-row__meta">8개</span><button class="sl-btn sl-btn--secondary sl-btn--sm">확인</button></div><div class="sl-row"><span class="sl-tile sl-tile--sm sl-tile--pink"><svg class="sl-ico sl-ico--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/><rect width="20" height="14" x="2" y="6" rx="2"/></svg></span><span class="sl-row__main">서비스 PM</span><span class="sl-row__meta">6개</span><button class="sl-btn sl-btn--secondary sl-btn--sm">확인</button></div><div class="sl-row sl-row--ai"><div class="sl-row__main"><div>교육운영 매니저 <span class="sl-row__meta">→ 교육 프로그램 운영</span></div><div class="sl-row__ai"><i class="sl-lens-dot"></i>렌지가 공개 직무 사전에서 찾았어요</div></div></div></div></div>
<div class="sl-cta"><div class="sl-cta__row"><button class="sl-btn sl-btn--secondary" data-prev>이전</button><button class="sl-btn sl-btn--primary" data-next>직무 확인 <span class="sl-btn__arrow">→</span></button></div></div></div>
<div class="sl-page" data-i="3" hidden><div class="head"><div class="sl-steps"><div class="sl-steps__label"><span>4/5</span><span>대상자, 기간</span><span style="color:var(--ink-subtle)">(1/2)</span></div><div class="sl-steps__track"><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__fill" style="width:calc((100% - 10px) * 0.75)"></i><i class="sl-steps__glide" style="left:calc(5px + (100% - 10px) * 0.75)"></i></div></div>
<div class="sl-top"><h1 class="sl-top__title">최대인원 1,500명 중<br><span class="sl-accent">1,248명</span>을 올렸어요</h1><p class="sl-top__desc">1,203명은 직무가 자동으로 연결됐어요.</p></div></div>
<div class="body sl-stagger"><div class="sl-card" style="padding:16px"><div class="cap" style="font:500 12px/16px var(--font-sans);color:var(--ink-muted);margin-bottom:8px">연결 현황</div><div class="sl-bar"><div class="sl-bar__seg--success" style="--w:96%;width:96%"></div><div class="sl-bar__seg--warning" style="--w:4%;width:4%"></div></div><div class="sl-bar-legend"><span><i class="sl-dot sl-dot--success"></i>자동 연결 1,203명</span><span><i class="sl-dot sl-dot--warning"></i>확인 필요 45명</span></div></div><div class="sl-row"><span class="sl-tile sl-tile--sm sl-tile--pink"><svg class="sl-ico sl-ico--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/><rect width="20" height="14" x="2" y="6" rx="2"/></svg></span><span class="sl-row__main">서비스 PM</span><span class="sl-row__meta">312명</span></div><div class="sl-row"><span class="sl-tile sl-tile--sm sl-tile--orange"><svg class="sl-ico sl-ico--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z"/><path d="M22 10v6"/><path d="M6 12.5V16a6 3 0 0 0 12 0v-3.5"/></svg></span><span class="sl-row__main">전문도 개발</span><span class="sl-row__meta">208명</span></div><button class="sl-btn sl-btn--link" style="align-self:flex-start">제외하고 계속</button></div>
<div class="sl-cta"><div class="sl-cta__row"><button class="sl-btn sl-btn--secondary" data-prev>이전</button><button class="sl-btn sl-btn--primary sl-btn--final" data-next>명단 확인 <span class="sl-btn__arrow">→</span></button></div></div></div>
<div class="sl-page sl-ambient" data-i="4" hidden><div class="head"><div class="sl-steps"><div class="sl-steps__label"><span>5/5</span><span>확인, 초대</span></div><div class="sl-steps__track"><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot is-done"></i><i class="sl-steps__line"></i><i class="sl-steps__dot"></i><i class="sl-steps__fill" style="width:calc((100% - 10px) * 1)"></i><i class="sl-steps__glide" style="left:calc(5px + (100% - 10px) * 1)"></i></div></div></div>
<div class="body" style="align-items:center;justify-content:center;text-align:center;gap:16px"><span class="sl-lens" aria-hidden="true"><svg viewBox="0 0 240 240" role="img" aria-label="SkillLens"><defs><linearGradient id="mkg4-gb" x1="0.7" y1="0" x2="0.25" y2="1"><stop offset="0" stop-color="#eceeff"/><stop offset="0.22" stop-color="#9a9cf8"/><stop offset="0.5" stop-color="#5450e9"/><stop offset="0.8" stop-color="#4f46e5"/><stop offset="1" stop-color="#4a44d8"/></linearGradient><linearGradient id="mkg4-gbe" x1="0" y1="0.2" x2="1" y2="0.8"><stop offset="0" stop-color="#f3f4ff"/><stop offset="0.35" stop-color="#cdd2ff" stop-opacity="0.9"/><stop offset="1" stop-color="#8f93f7" stop-opacity="0.3"/></linearGradient><radialGradient id="mkg4-gbg" cx="0.72" cy="0.18" r="0.75"><stop offset="0" stop-color="#fff" stop-opacity="0.55"/><stop offset="0.45" stop-color="#fff" stop-opacity="0.12"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></radialGradient><radialGradient id="mkg4-gbs" cx="0.35" cy="0.85" r="0.7"><stop offset="0" stop-color="#2e2bb8" stop-opacity="0.35"/><stop offset="1" stop-color="#2e2bb8" stop-opacity="0"/></radialGradient><linearGradient id="mkg4-gf" x1="0.1" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#fff" stop-opacity="0.5"/><stop offset="0.5" stop-color="#fff" stop-opacity="0.9"/><stop offset="0.78" stop-color="#f3ffe2"/><stop offset="0.92" stop-color="#d3ff9a"/><stop offset="1" stop-color="#b6ff75"/></linearGradient><linearGradient id="mkg4-go" x1="0.15" y1="0" x2="0.85" y2="1"><stop offset="0" stop-color="#b3ecff"/><stop offset="0.28" stop-color="#5fb0ff"/><stop offset="0.6" stop-color="#3f4fe3"/><stop offset="0.85" stop-color="#5f74f0"/><stop offset="1" stop-color="#8d9cf5"/></linearGradient><linearGradient id="mkg4-ge" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#fff"/><stop offset="0.6" stop-color="#fff" stop-opacity="0.85"/><stop offset="1" stop-color="#eaffd4" stop-opacity="0.4"/></linearGradient><clipPath id="mkg4-cb"><ellipse cx="-24" cy="0" rx="84" ry="98" ><animate attributeName="cx" from="-64" to="-24" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse></clipPath><clipPath id="mkg4-cbi"><ellipse cx="-21.5" cy="-1" rx="82" ry="96.5" ><animate attributeName="cx" from="-61.5" to="-21.5" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse></clipPath><clipPath id="mkg4-cf"><ellipse cx="24" cy="0" rx="84" ry="98" ><animate attributeName="cx" from="64" to="24" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse></clipPath></defs><g transform="translate(120 120) rotate(28)"><g clip-path="url(#mkg4-cb)"><ellipse cx="-24" cy="0" rx="84" ry="98" fill="url(#mkg4-gbe)"><animate attributeName="cx" from="-64" to="-24" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse><g clip-path="url(#mkg4-cbi)"><ellipse cx="-21.5" cy="-1" rx="82" ry="96.5" fill="url(#mkg4-gb)"><animate attributeName="cx" from="-61.5" to="-21.5" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse><ellipse cx="-21.5" cy="-1" rx="82" ry="96.5" fill="url(#mkg4-gbs)"><animate attributeName="cx" from="-61.5" to="-21.5" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse><ellipse cx="-21.5" cy="-1" rx="82" ry="96.5" fill="url(#mkg4-gbg)"><animate attributeName="cx" from="-61.5" to="-21.5" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse></g></g><ellipse cx="24" cy="0" rx="84" ry="98" fill="url(#mkg4-gf)"><animate attributeName="cx" from="64" to="24" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse><ellipse cx="24" cy="0" rx="84" ry="98" fill="url(#mkg4-go)" clip-path="url(#mkg4-cb)" opacity="0.93"><animate attributeName="cx" from="64" to="24" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse><g clip-path="url(#mkg4-cf)"><ellipse cx="24" cy="0" rx="84" ry="98" fill="url(#mkg4-ge)"><animate attributeName="cx" from="64" to="24" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse><ellipse cx="29" cy="-2" rx="82" ry="96" fill="url(#mkg4-gf)"><animate attributeName="cx" from="69" to="29" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse><ellipse cx="29" cy="-2" rx="82" ry="96" fill="url(#mkg4-go)" clip-path="url(#mkg4-cb)" opacity="0.93"><animate attributeName="cx" from="69" to="29" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse></g><ellipse cx="-24" cy="0" rx="83.5" ry="97.5" fill="none" stroke="#fff" stroke-width="1" opacity="0.6"><animate attributeName="cx" from="-64" to="-24" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse><ellipse cx="24" cy="0" rx="83.5" ry="97.5" fill="none" stroke="#fff" stroke-width="1" opacity="0.8"><animate attributeName="cx" from="64" to="24" dur="0.9s" fill="freeze" calcMode="spline" keyTimes="0;1" keySplines="0.65 0 0.15 1"/></ellipse></g></svg></span><h1 class="sl-done-screen__title sl-in sl-delay-3">AI 전환 진단을<br><span class="sl-accent">시작했어요</span></h1><p class="sl-done-screen__desc sl-in sl-delay-4"><span data-count="1248">0</span>명에게 초대를 보냈어요.</p></div>
<div class="sl-cta sl-in sl-delay-5"><button class="sl-btn sl-btn--primary" data-next>참가 현황 보기 <span class="sl-btn__arrow">→</span></button></div></div>
</div>
<script>
(function(){var stage=document.getElementById('stage'),pages=[].slice.call(stage.querySelectorAll('.sl-page')),cur=0,busy=false,rm=matchMedia('(prefers-reduced-motion: reduce)').matches;
function count(p){p.querySelectorAll('[data-count]').forEach(function(el){var n=+el.dataset.count;if(rm){el.textContent=n.toLocaleString();return}var t0=performance.now(),D=900;(function f(t){var k=Math.min(1,(t-t0)/D);k=1-Math.pow(1-k,3);el.textContent=Math.round(n*k).toLocaleString();if(k<1)requestAnimationFrame(f)})(t0)})}
function restart(p){p.querySelectorAll('.sl-stagger>*,.sl-in,.sl-bar>*').forEach(function(el){el.style.animation='none';void el.offsetWidth;el.style.animation=''})}
function go(to,back){if(busy||to===cur||to<0||to>=pages.length)return;busy=true;var a=pages[cur],b=pages[to];b.hidden=false;a.className=a.className.replace(/ is-\S+/g,'')+(back?' is-exit-back':' is-exit');b.className=b.className.replace(/ is-\S+/g,'')+(back?' is-enter-back':' is-enter');restart(b);count(b);setTimeout(function(){a.hidden=true;a.className=a.className.replace(/ is-\S+/g,'');busy=false;cur=to},rm?0:360)}
stage.addEventListener('click',function(e){var n=e.target.closest('[data-next]'),p=e.target.closest('[data-prev]');if(n)go(cur===pages.length-1?0:cur+1,false);if(p)go(cur-1,true)});
count(pages[0]);var auto=setInterval(function(){go(cur===pages.length-1?0:cur+1,false)},2600);stage.addEventListener('click',function(){clearInterval(auto)},{once:true});})();
</script>
이 사이트는 ideber 저장소 projects/skill-lens/ 에서 자동으로 만들어집니다. 고칠 때는 저장소를 고칩니다. 공개 주소이지만 검색엔진에는 나오지 않습니다.