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

로그인 UI 디자인 9종 — 회원가입부터 세션 만료까지

입력 완성도로 진행 표시가 다시 채워지고, 남은 유효시간이 매초 다시 구해져 링 각도로 바뀌고, 스크롤 진행률이 특정 지점을 넘어야 동의 칸이 열리는 로그인·회원가입 UI 9종입니다.

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

데모

아홉 화면은 이메일·비밀번호·인증 코드처럼 사람이 채워 넣는 값 대신, 그 값이 채워진 정도·흐른 시간·스크롤한 비율 같은 상태 하나를 계산해 화면을 바꿉니다. 09 동의 체크박스만 실제 스크롤에 반응하고, 나머지 여덟 개는 정해진 시나리오가 rAF 로 자동 재생되며 값이 바뀌는 과정을 반복해서 보여줍니다. 실키·실 서버 검증·실제 메일 발송은 어디에도 없고 전부 화면 안에서 끝나는 시뮬레이션입니다. 화면 크기는 480×300 으로 고정해 24장을 찍고, 그 장 사이 간격 23개를 실제 움직임의 기준으로 삼습니다.

실측 한눈에

항목 초점 누적면적(%) 강도평균 움직인프레임(23 기준)
01 로그인 카드 입력 완성도로 진행 표시 재계산 0.824 155.2 19
02 회원가입 단계 단계 진행률로 막대 길이 재계산 2.294 177.4 23
03 소셜 로그인 버튼 개수로 열 수 재계산 23.165 161.0 23
04 매직 링크 잔여시간으로 링 호 길이 재계산 2.65 153.0 23
05 2단계 인증 채운 자리수 비율로 버튼 상태 재계산 9.225 49.4 22
06 비밀번호 재설정 요청 이메일 점수로 버튼·색 재계산 7.964 159.4 20
07 세션 만료 경과 시간으로 강조 농도 재계산 4.845 31.8 23
08 캡차 위젯 선택 일치율로 테두리·버튼 재계산 4.765 71.6 7
09 동의 체크박스 스크롤 진행률로 활성 시점 재계산 15.528 144.1 23

면적이 작아도 계산이 쉬는 건 아니다

01 로그인 카드(0.824%)·02 회원가입 단계(2.294%)·04 매직 링크(2.65%)는 입력 칸 테두리·진행 막대·도넛 링처럼 원래 차지하는 면적이 작은 요소라 누적면적이 낮게 나오는 게 자연스러운 결과입니다. 08 캡차 위젯은 움직인프레임이 7로 다른 항목보다 적은데, 이는 결함이 아니라 자리 선택이 정해진 간격마다 한 번씩 일어나고 그 사이에는 값을 그대로 유지하는 시나리오 자체의 정지 구간입니다.

로그인·회원가입 UI 의 해부 — 아홉 화면이 계산하는 것

로그인·회원가입 화면은 흔히 칸이 채워졌는지, 몇 단계가 남았는지, 언제 만료되는지를 정적인 문구로 박아 두지만, 이 아홉 화면은 그 값 하나를 계산해 표시나 상태를 다시 정합니다. 클래스를 열고 닫는 전환이 아니라 완성 비율·잔여시간·일치율처럼 숫자를 다시 구하는 계산이 매번 화면을 채웁니다.

자동재생과 실사용자 반응이 갈리는 지점

01부터 08까지는 rAF 루프나 고정 시각을 기준으로 값이 저절로 흘러가는 시뮬레이션이고, 실제 스크롤에 반응해 값을 다시 재는 쪽은 09 동의 체크박스 하나뿐입니다. 09를 뺀 나머지 여덟 화면은 이메일을 입력하거나 코드를 채우는 실제 조작 대신, 미리 정한 시나리오가 그 과정을 그대로 재현합니다.

아홉 화면이 각자 구하는 값

01은 이메일·비밀번호 칸이 채워진 개수로 완성 비율을 구하고, 02는 현재 단계를 전체 단계로 나눠 진행률을 구하며, 03은 버튼 개수로 한 줄에 놓을 열 수를 다시 구합니다. 04는 남은 유효시간을 매초 다시 구해 링의 호 길이로 바꾸고, 05는 채운 자리수 비율로 확인 버튼 상태를 정하며, 06은 이메일 구성을 검사해 유효성 점수를 구합니다. 07은 세션이 끊긴 뒤 흐른 시간으로 강조 농도를 다시 구하고, 08은 선택 칸과 정답 칸의 일치율을 구하며, 09는 약관을 스크롤한 진행률로 읽음 판정 지점을 계산합니다.

아홉 화면이 공유하는 조건

아홉 화면 모두 지금까지 쌓인 흔적(채워진 글자 수·지난 단계·흐른 시간·스크롤한 거리) 하나를 입력으로 받아 그 값을 계산에 그대로 되먹인다는 점이 같습니다. 01·05·08은 채움·선택 개수를 세는 쪽이고, 04·07은 시간이 흐른 만큼 값을 다시 구하는 쪽이며, 03·09는 화면에 있는 요소의 실제 렌더 값(개수·스크롤 위치)을 재는 쪽입니다.

화면별 코드

아홉 화면 각각에서 계산 부분만 골라 담았고, 전체 마크업과 스타일시트는 압축 파일 안에 들어 있습니다.

01로그인 카드 — 입력 완성도를 계산해 진행 표시를 채우는 카드

웹 서비스 로그인 화면이나 앱 로그인 모달 같은 모바일 로그인 ui 에서, 이메일과 비밀번호 칸이 채워진 완성도를 눈으로 보여주고 싶을 때 쓰는 형태입니다.

채운 글자 수를 세어 완성 비율을 다시 구하는 계산

이메일·비밀번호 칸이 채워진 글자 수를 세어 전체 길이 대비 비율을 구하고, 그 비율을 카드 테두리의 conic-gradient 진행 표시에 그대로 반영합니다.

  function frameFor(t) {
    var emailChars = Math.min(Math.max(Math.floor(t / TYPE_MS), 0), EMAIL_LEN);
    var pwStart = EMAIL_LEN * TYPE_MS;
    var pwChars = t > pwStart
      ? Math.min(Math.max(Math.floor((t - pwStart) / TYPE_MS), 0), SAMPLE_PW_LEN)
      : 0;
    return { emailChars: emailChars, pwChars: pwChars };
  }

  function apply(t) {
    var f = frameFor(t);
    emailEl.value = SAMPLE_EMAIL.slice(0, f.emailChars);
    pwEl.value = PW_DOTS.slice(0, f.pwChars);
    var ratio = ((f.emailChars / EMAIL_LEN) + (f.pwChars / SAMPLE_PW_LEN)) / 2;
    ring.style.setProperty('--ratio', ratio.toFixed(4));
  }
로그인 카드 — 입력 완성도를 계산해 진행 표시를 채우는 카드
새 창에서 열기

01 · 로그인 카드 — 입력 완성도를 계산해 진행 표시를 채우는 카드 — 측정 누적면적 0.824% · 움직인 프레임 19/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

conic-gradientsetPropertyautocomplete

02회원가입 단계 — 진행률을 직접 나눠 구해 막대 길이와 색을 정하는 단계형 폼

여러 단계로 나뉜 회원가입 화면 디자인에서 지금 몇 번째 단계인지 막대 하나로 보여주는 형태입니다.

단계 경계와 단계 안 경과분을 함께 더하는 계산

현재 단계 번호를 전체 단계 수로 나눈 값에 그 단계 안에서 흐른 경과분을 더해, 막대가 정수 단계마다 뚝뚝 끊기지 않고 조금씩 자라도록 진행률을 다시 구합니다.

  function apply(t) {
    var tt = t % CYCLE_MS;
    var idx = Math.min(Math.max(Math.floor(tt / STEP_MS), 0), STEP_TOTAL - 1);
    var current = idx + 1;
    // 단계 경계는 정수(1~4)로 딱딱 끊어 aria·라벨에 반영하되, 막대 자체는 단계 안의 경과분(0~1)을
    // 더해 매 프레임 조금씩 자라게 한다 — 계산 한 겹(보간)으로 실제 회원가입 진행바처럼 부드럽다.
    var within = (tt % STEP_MS) / STEP_MS;
    var ratio = (idx + within) / STEP_TOTAL;
    track.style.setProperty('--ratio', ratio.toFixed(4));
    track.setAttribute('aria-valuenow', String(current));
    steps.forEach(function (el, i) {
      if (i === idx) {
        el.classList.add('is-active');
      } else {
        el.classList.remove('is-active');
      }
    });
  }
회원가입 단계 — 진행률을 직접 나눠 구해 막대 길이와 색을 정하는 단계형 폼
새 창에서 열기

02 · 회원가입 단계 — 진행률을 직접 나눠 구해 막대 길이와 색을 정하는 단계형 폼 — 측정 누적면적 2.294% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

setPropertyaria-valuenowclassList

03소셜 로그인 — 버튼 개수로 열 수를 다시 구해 항상 고르게 배분하는 묶음

가입 옵션이 늘었다 줄었다 하는 소셜 로그인 ui 영역에서 버튼 배치가 흐트러지지 않게 만드는 형태입니다.

버튼 개수로 열 수와 남은 구간을 다시 재는 계산

제공자 버튼 개수를 세어 한 줄에 놓을 열 수를 다시 구하고, 다음 개수 전환까지 남은 구간도 매 프레임 함께 계산해 그리드 재배치가 갑자기 튀지 않게 만듭니다.

  function colsFor(n) {
    return n <= 3 ? n : Math.ceil(n / 2);
  }

  function apply(t) {
    var tt = t % CYCLE_MS;
    var idx = Math.min(Math.max(Math.floor(tt / STEP_MS), 0), COUNTS.length - 1);
    var n = COUNTS[idx];
    var cols = colsFor(n);
    row.style.setProperty('--cols', String(cols));
    hintCount.textContent = String(n);
    btns.forEach(function (btn, i) {
      if (i < n) {
        btn.classList.remove('is-hidden');
      } else {
        btn.classList.add('is-hidden');
      }
    });
    // 다음 개수 전환까지 남은 구간을 매 프레임 다시 계산해 가는 줄(계산 한 겹) —
    // 그리드 재배치가 갑자기 튀지 않고 다음 변화가 다가옴을 예고한다.
    var within = (tt % STEP_MS) / STEP_MS;
    tickBar.style.setProperty('--within', within.toFixed(4));
  }
소셜 로그인 — 버튼 개수로 열 수를 다시 구해 항상 고르게 배분하는 묶음
새 창에서 열기

03 · 소셜 로그인 — 버튼 개수로 열 수를 다시 구해 항상 고르게 배분하는 묶음 — 측정 누적면적 23.165% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

grid-template-columnsclip-pathclassList

04매직 링크 — 남은 유효시간을 다시 구해 링의 호 길이로 보여주는 발송 완료 카드

비밀번호 없는 로그인 안내 화면에서 링크가 아직 살아있는지를 숫자 대신 링 하나로 보여주는 형태입니다.

경과 비율을 유효시간과 호 길이로 함께 환산하는 계산

주기 안에서 흐른 비율을 구하고, 그 비율을 전체 유효시간(VALID_SEC)에 곱해 남은 초를 표시하는 동시에 도넛 링의 둘레(CIRCUMFERENCE)에서 뺀 값으로 stroke-dashoffset을 다시 그립니다.

  var VALID_SEC = 300; // 변형: 300 → 900
  var CIRCUMFERENCE = 276.46;
  var CYCLE_MS = 2000;

  function ratio(t) {
    return 1 - Math.min(Math.max(t / CYCLE_MS, 0), 1);
  }

  function apply(t) {
    var r = ratio(t);
    var remainingDisplaySec = Math.ceil(r * VALID_SEC);
    ring.style.strokeDashoffset = String(CIRCUMFERENCE * (1 - r));
    timeText.textContent = '남은 시간' + ' ' + remainingDisplaySec + '초';
  }
매직 링크 — 남은 유효시간을 다시 구해 링의 호 길이로 보여주는 발송 완료 카드
새 창에서 열기

04 · 매직 링크 — 남은 유효시간을 다시 구해 링의 호 길이로 보여주는 발송 완료 카드 — 측정 누적면적 2.65% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

stroke-dasharraystrokeDashoffsetrequestAnimationFrame

052단계 인증 — 채운 자리수 비율로 확인 버튼 상태를 정하는 코드 입력

OTP 인증 코드 입력처럼 여섯 자리를 하나씩 채워 나가는 화면에서 마지막 자리까지 채워야 확인 버튼이 열리는 형태입니다.

결정적 난수로 자리마다 채워지는 시점을 미리 정하는 계산

mulberry32(42)로 만든 결정적 난수로 여섯 자리 코드를 미리 정해 두고, 자리마다 DIGIT_MS 간격으로 채워지는 시점을 계산해 채운 자리수 비율이 100%에 닿을 때만 확인 버튼의 불투명도와 눌림 가능 여부를 함께 바꿉니다.

  function mulberry32(seed) {
    return function () {
      seed |= 0; seed = (seed + 0x6D2B79F5) | 0;
      var t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
      t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
      return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
    };
  }

  var rand = mulberry32(42);
  var code = [];
  for (var i = 0; i < DIGITS; i++) code.push(Math.floor(rand() * 10));

  function filled(t) {
    return Math.min(Math.max(Math.floor(t / DIGIT_MS), 0), DIGITS);
  }
2단계 인증 — 채운 자리수 비율로 확인 버튼 상태를 정하는 코드 입력
새 창에서 열기

05 · 2단계 인증 — 채운 자리수 비율로 확인 버튼 상태를 정하는 코드 입력 — 측정 누적면적 9.225% · 움직인 프레임 22/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

data-indexautocompletesetAttribute

06비밀번호 재설정 요청 — 이메일 형식 점수를 계산해 버튼 상태를 정하는 폼

비밀번호 찾기 폼처럼 이메일 한 칸만 있는 화면에서 형식이 맞는지를 미리 점수로 계산해 보여주는 형태입니다.

골뱅이·도메인·길이 세 조각을 더해 점수를 구하는 계산

골뱅이 포함 여부에 .4점, 도메인 형식에 .4점, 전체 길이 비율에 .2점을 더해 유효성 점수를 직접 구하고, 그 점수 구간에 따라 요청 버튼의 활성화 여부와 안내 문구 색을 함께 정합니다.

  function currentText(t) {
    var n = Math.min(Math.max(Math.floor(t / TYPE_MS), 0), SAMPLE.length);
    return SAMPLE.slice(0, n);
  }

  function score(text) {
    var domain = text.split('@')[1] || '';
    var s = 0;
    if (text.indexOf('@') !== -1) s += .4;
    if (/\.[a-z]{2,}$/i.test(domain)) s += .4;
    s += Math.min(text.length / 12, 1) * .2;
    return s;
  }
비밀번호 재설정 요청 — 이메일 형식 점수를 계산해 버튼 상태를 정하는 폼
새 창에서 열기

06 · 비밀번호 재설정 요청 — 이메일 형식 점수를 계산해 버튼 상태를 정하는 폼 — 측정 누적면적 7.964% · 움직인 프레임 20/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

aria-invalidaria-describedbyclassList

07세션 만료 — 끊긴 뒤 흐른 시간으로 강조 농도를 다시 구하는 알림

장시간 미사용 세션 알림처럼 방치된 시간이 길수록 다급함을 더 강하게 보여줘야 하는 형태입니다.

색을 섞는 비율에 거듭제곱을 걸어 농도를 구하는 계산

세션이 끊긴 뒤 흐른 시간을 RAMP_MS 대비 비율로 구하고, 그 비율에 INTENSITY_POW 거듭제곱을 걸어 만든 강도값으로 바탕색과 강조색 사이 RGB를 섞어 배지 색과 버튼 확대율을 함께 정합니다.

  function elapsedRatio(t) { return clamp(t / RAMP_MS, 0, 1); }

  var cs = getComputedStyle(badge);
  var paperRgb = hexToRgb(cs.getPropertyValue('--paper'));
  var errorRgb = hexToRgb(cs.getPropertyValue('--error'));

  function apply(t) {
    var ratio = elapsedRatio(t);
    var intensity = Math.pow(ratio, INTENSITY_POW);

    var r = Math.round(paperRgb[0] + (errorRgb[0] - paperRgb[0]) * intensity);
    var g = Math.round(paperRgb[1] + (errorRgb[1] - paperRgb[1]) * intensity);
    var b = Math.round(paperRgb[2] + (errorRgb[2] - paperRgb[2]) * intensity);
    badge.style.backgroundColor = 'rgb(' + r + ',' + g + ',' + b + ')';
    badge.classList.toggle('isHot', intensity > 0.5);

    btn.style.transform = 'scale(' + (1 + intensity * 0.04) + ')';

    elapsedSeconds.textContent = String(Math.round(ratio * (RAMP_MS / 1000)));
  }
세션 만료 — 끊긴 뒤 흐른 시간으로 강조 농도를 다시 구하는 알림
새 창에서 열기

07 · 세션 만료 — 끊긴 뒤 흐른 시간으로 강조 농도를 다시 구하는 알림 — 측정 누적면적 4.845% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

getComputedStylegetPropertyValueclassList

08캡차 위젯 — 선택 일치율을 직접 구해 테두리 색과 버튼 상태를 정하는 자리

회원가입 전 사람 확인 단계에서 정답 칸과 선택한 칸이 얼마나 겹치는지를 직접 계산해 보여주는 형태입니다.

정답 배열과 선택 배열을 대조해 일치율을 구하는 계산

정해진 순서대로 하나씩 선택되는 칸을 정답 배열과 대조해 겹치는 개수를 세고, 그 일치율이 기준(MATCH_THRESHOLD)을 넘어야만 확인 버튼이 활성화되도록 계산합니다.

  function selectedSoFar(t) {
    var count = clamp(Math.floor(t / PICK_MS), 0, PICK_ORDER.length);
    return PICK_ORDER.slice(0, count);
  }

  function matchRatioOf(selected) {
    var hit = 0;
    for (var i = 0; i < ANSWER.length; i++) {
      if (selected.indexOf(ANSWER[i]) !== -1) hit += 1;
    }
    return clamp(hit / ANSWER.length, 0, 1);
  }

  function apply(t) {
    var selected = selectedSoFar(t);
    tiles.forEach(function (tile) {
      var idx = Number(tile.getAttribute('data-index'));
      tile.classList.toggle('isPicked', selected.indexOf(idx) !== -1);
    });
    var ratio = matchRatioOf(selected);
    matchPercent.textContent = String(Math.round(ratio * 100));
    submitBtn.disabled = ratio < MATCH_THRESHOLD;
  }
캡차 위젯 — 선택 일치율을 직접 구해 테두리 색과 버튼 상태를 정하는 자리
새 창에서 열기

08 · 캡차 위젯 — 선택 일치율을 직접 구해 테두리 색과 버튼 상태를 정하는 자리 — 측정 누적면적 4.765% · 움직인 프레임 7/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

data-indexgrid-template-columnsclassList

09동의 체크박스 — 약관 스크롤 진행률을 재서 활성 시점을 정하는 UI

약관 동의 모달처럼 끝까지 읽었다는 근거가 필요한 화면에서 스크롤 위치만으로 그 근거를 계산하는 형태입니다.

실제 스크롤 값을 재 임계값과 비교하는 계산 — 09만의 실사용자 반응

패널의 scrollHeight와 clientHeight 차이로 최대 스크롤량을 구하고, 지금 스크롤한 위치를 그 값으로 나눈 진행률이 SCROLL_THRESHOLD를 넘어서는 순간에만 체크박스를 눌림 가능한 상태로 바꿉니다. 아홉 화면 중 실제 스크롤 이벤트로 값을 다시 재는 쪽은 이 화면 하나뿐입니다.

  function onScroll() {
    var maxScroll = panel.scrollHeight - panel.clientHeight;
    var progress = maxScroll > 0 ? clamp(panel.scrollTop / maxScroll, 0, 1) : 1;
    if (progress >= SCROLL_THRESHOLD && !unlocked) {
      unlocked = true;
      checkbox.disabled = false;
      checkbox.setAttribute('aria-disabled', 'false');
      label.textContent = DONE_TEXT;
    } else if (progress < SCROLL_THRESHOLD && unlocked) {
      unlocked = false;
      checkbox.disabled = true;
      checkbox.checked = false;
      checkbox.setAttribute('aria-disabled', 'true');
      label.textContent = lockedText;
    }
  }
동의 체크박스 — 약관 스크롤 진행률을 재서 활성 시점을 정하는 UI
새 창에서 열기

09 · 동의 체크박스 — 약관 스크롤 진행률을 재서 활성 시점을 정하는 UI — 측정 누적면적 15.528% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

scrollTopaddEventListenersetAttribute

어디에 쓰는 화면인가 — 로그인·회원가입 폼을 새로 짜는 팀

로그인 폼을 다시 짜는 팀이 이 아홉 화면을 찾는 이유는 대체로 하나입니다. 01 처럼 입력 완성도를 진행 표시로 보여주는 카드를 붙이고 싶은데, 그 진행률을 어떤 기준으로 계산해야 할지가 막막하기 때문입니다.

비밀번호 재설정 화면을 맡은 사람은 06 처럼 이메일 형식만 보고 버튼 상태를 미리 켤지 결정하는 판단을 자주 마주칩니다. 형식 검사와 실제 발송 성공 여부를 같은 화면에서 어떻게 구분해 보여줄지가 그 다음 문제입니다.

약관 동의 화면을 만드는 사람에게는 09 의 스크롤 진행률 계산이 곧 화면의 전부입니다. 스크롤을 끝까지 밀어야 동의 버튼이 켜지는 조건을 어느 시점에서 판정할지에 따라 사용자가 느끼는 답답함이 달라집니다.

reduced-motion 을 포함한 세 가지 변형

값 하나를 바꾸면 화면 세 곳에서 느낌이 서로 다르게 갈립니다.

이름 바꾼 값 느낌
매직 링크 유효시간 04 VALID_SEC 300 → 900 유효시간을 300초(5분)로 두면 링이 빠르게 줄어들어 서두르게 되지만 보안엔 유리하고, 900초(15분)로 늘리면 여유는 생기지만 링이 거의 안 줄어드는 것처럼 보여 링크가 살아있다는 감각이 흐려진다
세션 만료 강조 곡선 07 INTENSITY_POW 1 → 3 지수를 1로 두면 경과 시간에 비례해 배지 색이 완만하게 짙어져 다급함이 덜 느껴지고, 3으로 올리면 초반엔 거의 그대로 있다가 막판에 갑자기 진해져 오래 방치했다는 경고가 강하게 온다
동의 체크박스 스크롤 임계값 09 SCROLL_THRESHOLD .7 → 1 임계값을 .7로 두면 약관을 70%만 훑어도 체크박스가 열려 가입은 빨라지지만 다 읽었다는 보장이 약하고, 1로 두면 끝까지 스크롤해야 열려 확실하지만 긴 약관에서는 지루하게 느껴질 수 있다

접근성 — 계산은 남기고 애니메이션만 끈다

아홉 화면은 prefers-reduced-motion을 읽으면 자동 시나리오를 돌리는 rAF 루프 자체를 걸지 않고, 정해진 한 지점의 상태만 계산해 고정합니다. 05 2단계 인증은 애니메이션이 꺼지면 여섯 자리가 채워지는 과정 없이 곧바로 빈 칸에 확인 버튼이 비활성화된 초기 상태로 고정되고, 09 동의 체크박스는 자동 스크롤 시뮬레이션만 멈출 뿐 실제 스크롤에 따른 진행률 계산은 그대로 동작합니다. aria-valuenow·aria-invalid·aria-disabled 같은 속성은 애니메이션 여부와 무관하게 항상 실제 상태를 반영합니다.

값이 화면을 바꾸는 곳 — 완성도·잔여시간·읽은 비율

로그인·회원가입 UI 를 만들 때 이 세 축(완성도·잔여시간·읽은 비율)을 데이터로 다루면, 칸 개수나 유효시간이 바뀌어도 표시 로직을 다시 짤 필요가 없어집니다.

완성도가 바꾸는 것

01은 이메일·비밀번호 칸이 채워진 글자 수를 전체 길이와 비교해 완성 비율을 구하고, 05는 여섯 자리 중 채워진 자리수 비율을 구합니다. 두 값 모두 100%에 닿기 전까지는 진행 표시나 확인 버튼이 그 비율만큼만 반응하다가, 100%가 되는 순간에야 버튼이 완전히 열립니다.

잔여시간이 바꾸는 것

04는 주기 안에서 흐른 비율을 유효시간(VALID_SEC)과 곱해 남은 초를 구하고 동시에 링의 호 길이로 환산하며, 07은 세션이 끊긴 뒤 흐른 시간을 RAMP_MS 대비 비율로 구해 배지 색 농도에 거듭제곱을 걸어 반영합니다. 두 화면 다 시간이라는 값 하나가 숫자 표시와 시각 강도 두 곳을 동시에 바꿉니다.

읽은 비율이 바꾸는 것

09는 패널을 스크롤한 위치를 최대 스크롤량으로 나눈 진행률을 실시간으로 구하고, 그 진행률이 SCROLL_THRESHOLD를 넘는지 아닌지만으로 체크박스의 눌림 가능 여부와 안내 문구를 함께 바꿉니다. 임계값을 넘기 전까지는 스크롤을 오래 해도 값이 매끄럽게 이어지다가, 넘는 순간에만 상태가 뒤집힙니다.

무엇이 먼저 깨지는가 — 빈 이메일·만료 직전·정답 칸 0개

세 지점 다 계산 자체는 멈추지 않고 끝까지 돌지만, 입력값의 경계를 미리 잡아 두지 않으면 화면에는 그 어색한 결과가 그대로 드러납니다.

이메일 칸이 비어 있는 경우

06의 score 함수는 빈 문자열을 넘겨받으면 골뱅이도 도메인도 없어 세 조각 점수가 전부 0이 되므로, 요청 버튼은 비활성 상태를 유지하고 안내 문구도 "이메일 형식을 확인해 주세요"로 고정됩니다. 다만 이 계산은 글자가 하나도 없는 빈 칸과 골뱅이 없이 아무 글자만 채운 경우를 값 하나로 구분하지 못해(골뱅이가 없으면 두 경우 모두 .4점 아래에 머물러 같은 문구로 묶입니다), 실제 서비스에서는 빈 칸과 형식 오류에 서로 다른 안내 문구를 얹는 처리가 앞단에 있어야 합니다.

만료 직전인 경우

04의 ratio 함수는 주기(CYCLE_MS)를 다 채운 순간 0을 돌려주는데, 이 0은 "유효시간이 다 됐다"는 뜻과 "막 새로 발송됐다"는 뜻을 값 하나로 구분하지 못합니다. ydncqy9n 안 소스에는 이 CYCLE_MS 주기를 VALID_SEC 실제 초 단위로 한 번만 환산해 만료 뒤에는 링 갱신 자체를 멈추는 조건 분기가 비어 있어, 실제로 붙일 때는 만료 시점 이후를 걸러내는 조건 하나를 더해야 합니다.

정답 칸이 0개인 경우

08의 matchRatioOf는 ANSWER 배열의 길이로 나누는 계산이라 정답 칸이 하나도 없게 설정되면 나눗셈 자체가 성립하지 않아, 실제로 쓸 때는 정답 배열이 비어 있지 않은지부터 검사한 뒤 이 함수를 불러야 합니다.

로그인 폼을 붙이기 전에 자주 확인하는 것들

아홉 화면을 전부 한 로그인 페이지에 붙여야 하나요?

아닙니다. 01 로그인 카드와 04 매직 링크는 서로 다른 로그인 방식이라 하나만 골라 쓰면 되고, 02·03·09처럼 회원가입 흐름에서만 필요한 화면은 로그인 화면에는 붙이지 않아도 됩니다. 아홉 종은 각자 독립된 계산이라 필요한 화면만 골라 붙일 수 있습니다.

소셜 로그인 버튼에 실제 구글·카카오 같은 프로바이더가 연동돼 있나요?

아닙니다. 03 소셜 로그인은 버튼 개수로 열 수를 다시 구하는 배치 계산만 담당하는 가상 프로바이더 묶음이고, 실제 OAuth 연동이나 실키는 어디에도 들어 있지 않습니다. 실제 서비스에 붙이려면 각 프로바이더의 인증 절차를 서버 쪽에 별도로 구현해야 합니다.

실제 서버 인증과 연결하려면 무엇을 더해야 하나요?

이 데모는 화면 표시 계산만 담당하므로, 실제 인증 서버와 연결하려면 이메일 검증·인증 코드 발급·세션 발급 같은 로직을 서버 쪽에 구현하고 그 응답 값으로 SAMPLE_EMAIL·code·VALID_SEC 같은 자리표시자를 채워 넣는 코드만 더하면 됩니다. 화면에 값을 채워 넣는 계산 부분은 그대로 두고 데이터 출처만 바꿔 붙이면 됩니다.

더 읽을거리

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

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