국내 UI 패턴 중급 검토 중

풀와이드 Sticky CTA (토스식)

Full-width Sticky CTA토스 버튼키보드 위 고정 버튼Bottom Action Button

화면 하단(키보드가 올라오면 키보드 바로 위)에 고정되는 단일 큰 액션 버튼이에요. 토스와 뱅크샐러드가 자리 잡게 만든 모양입니다.

설명

한국 핀테크 앱이 자리 잡게 만든 모양이에요. 폼이나 온보딩에서 다음 액션을 한 손 엄지로 지연 없이 누를 수 있게 도와줍니다. 1열 폼과 함께 자연스러운 흐름을 만들고, 키보드가 올라오면 버튼이 키보드 위로 따라 올라오는 동작이 가장 중요해요. 일반 sticky bottom과는 이 부분이 달라요. 한 화면에 1차 액션 하나만 노출하기 때문에 사용자가 다음에 뭘 할지 헷갈리지 않습니다.

🖼️ 미니어처

다음

💬 AI에게 이렇게 말하세요

  1. 토스 앱처럼 화면 하단에 풀와이드 단일 CTA 버튼을 고정해 주세요. 키보드가 올라오면 키보드 바로 위에 붙도록 visualViewport API로 처리합니다.
  2. height 56px, font 16px, border-radius 12px의 풀와이드 primary 버튼으로 만들어 주세요. 좌우 padding 16px, safe-area-inset-bottom 처리 포함.
  3. 폼 검증이 통과되면 활성, 안 되면 비활성(60% opacity)으로 처리합니다.

왜 토스식인가요

한국 모바일 앱은 한 손 엄지 사용 비율이 높아요. 토스는 모든 폼·온보딩에서 '한 화면 한 액션'을 강제하면서 다음 액션 버튼을 항상 같은 자리(엄지 도달 영역)에 두는 룰을 정착시켰습니다. 사용자는 다음 액션을 찾을 필요가 없고, 화면이 바뀌어도 동일한 위치에서 동일한 모양의 버튼을 눌러요.

키보드 추적 코드

useEffect(() => {
  const vv = window.visualViewport
  if (!vv) return
  const onResize = () => {
    const offset = window.innerHeight - vv.height - vv.offsetTop
    document.documentElement.style.setProperty('--keyboard-offset', `${offset}px`)
  }
  vv.addEventListener('resize', onResize)
  vv.addEventListener('scroll', onResize)
  return () => {
    vv.removeEventListener('resize', onResize)
    vv.removeEventListener('scroll', onResize)
  }
}, [])

⚡ 사용 예 (한 줄)

<div className="fixed inset-x-0 bottom-0 px-4 pb-[env(safe-area-inset-bottom)] bg-white"><Button size="lg" className="w-full h-14">다음</Button></div>

🧩 컴포넌트 매핑

shadcn/ui Button(size="lg")에 Tailwind 'fixed bottom-0 inset-x-0 px-4 pb-[env(safe-area-inset-bottom)]'를 적용합니다. 키보드 추적은 window.visualViewport의 'resize'와 'scroll' 이벤트로 처리해요.

🚫
이렇게 하지 마세요

1차 액션이 하나가 아닌데 버튼을 2~3개 한 줄에 박아 두면 풀와이드 CTA의 명확성이 사라져요.

🇰🇷
국내 UI 특징

토스가 처음 자리 잡게 했지만 카카오뱅크와 뱅크샐러드, 쏘카, 당근까지 같은 모양으로 퍼졌어요. iOS Safari에서는 visualViewport 계산이 빠지면 버튼이 키보드에 가려지고, safe-area-inset-bottom 처리를 안 하면 노치 단말 하단에서 잘립니다. 글자 크기는 14px이 아니라 16~18px이 적당해요. 한국 모바일 사용자는 글자가 작은 CTA를 진지하지 않은 버튼으로 받아들이는 경향이 있습니다.

♿
접근성

비활성 상태를 색만으로 표현하지 마세요(aria-disabled + 안 누르는 이유 텍스트 표시). 폼 검증 실패 시 버튼을 disabled로 두기보다, 누르면 첫 에러 필드로 스크롤+포커스를 이동시키는 편이 더 친절해요.

사전 인덱스로