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

css 버튼 색상 변경 9가지 — hover 중간 색이 탁해지지 않게 계산한 장면

버튼 색을 hover 에서 바꾸는 건 한 줄이면 되지만, 그 줄은 중간 색을 탁하게 만들고 그라데이션은 아예 움직이지 못하게 하고 글자는 중간에 안 읽히게 둔다 — 02번·04번·07번이 하나씩 막는다.

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

css 버튼 색상 변경 9가지 — 색은 계산해서 옮겨야 중간이 맑다

아홉 장면은 색이 도착하는 방식이 단순한 것부터 놓았다. 01 은 남은 거리의 일정 비율씩 목표로 다가가는 기본 hover 이고, 02 는 같은 두 색을 그냥 섞은 버튼과 밝기를 보정해 섞은 버튼의 나란히 비교다. 03 은 그라데이션 색 경계가 스프링으로 밀려가는 장면, 04 는 두 겹을 포개 그라데이션을 바꾸는 크로스페이드, 05 는 각도가 포인터 쪽으로 따라 도는 장면이다. 06 은 누르는 동안 색상이 가속하는 버튼, 07 은 바탕이 밝아지면 글자색이 뒤집히는 버튼, 08 은 기울어진 빛 띠가 한 번 훑는 광택, 09 는 바탕색을 따라 그림자 색이 번지는 버튼이다.

이런 화면에서 쓴다

주요 행동 버튼이 마우스를 올리면 색이 바뀌는 화면 어디서나 쓴다. 가격표의 구매 버튼처럼 눈에 띄어야 하는 자리는 03·08 의 그라데이션이, 색을 고르는 도구 화면은 06 의 눌러서 돌리는 입력이, 바탕색이 여러 갈래로 바뀌는 테마 버튼은 07 의 글자 뒤집힘이 먼저 필요하다. 어느 쪽이든 색 한 쌍을 정해 두면 계산은 그 두 값 사이의 진행도 하나로 정리된다.

이웃 편과 무엇이 다른가

css 버튼 마우스 오버 효과 9가지 — 거리 값 하나로 갈라진다는 포인터가 얼마나 가까운지에 따라 버튼의 반응이 갈라지는 편이고, 버튼 눌림 효과 UI 9종 — 눌림 값이 되돌아오는 아홉 가지 방식은 눌렸다가 돌아오는 움직임을 다룬다. 이 편은 움직이는 대상이 모양이 아니라 색이어서, 중간 색을 어떻게 계산하느냐 하나에 아홉 장면을 걸었다.

기법별 코드로 보는 색 옮기기

아홉 장면 모두 네이티브 <button> 으로 만들었고(02·04 는 비교용으로 두 개), 색 계산은 전부 JS 가 프레임마다 한다. 01·02·07·09 는 색을 --c-from·--c-to 두 CSS 변수에 두고 getComputedStyle 로 읽어 쓴다. 아래에는 그 계산의 핵심 구간만 소스에서 그대로 발췌했으며, 입력이 없을 때의 자동 시연은 첫 포인터·키 입력이 오면 꺼지고 같은 계산이 입력을 받는다. 라이브러리와 CDN 은 쓰지 않았고 마크업·스타일 전체는 아래 압축 파일에 들어 있다.

01색을 목표로 끌어당기는 기본 hover

매 프레임 1 - exp(-dt * PULL_RATE) 비율을 세 채널의 남은 거리에 곱해 현재 색이 목표로 다가가고, 남은 거리 합이 SETTLE_GAP 미만이면 목표로 스냅한다. 시간 곡선이 없어 hover 를 도중에 놓아도 지금 색에서 바로 되돌아가기 시작한다. 01 항목은 누적면적 16.2%·강도 평균 114.6·움직인 프레임 22/23 이다.

색을 목표로 끌어당기는 기본 hover
새 창에서 열기

01 · 색을 목표로 끌어당기는 기본 hover — 측정 누적면적 16.203% · 움직인 프레임 22/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

PULL_RATESETTLE_GAPCYCLE_MS
  function tick(ts) {
    if (t0 === null) t0 = ts;
    var now = ts - t0;
    var dt = lastTs === null ? 0.016 : Math.min(0.05, (ts - lastTs) / 1000);
    lastTs = ts;
    var goal = target(now);
    var k = 1 - Math.exp(-dt * PULL_RATE);
    for (var i = 0; i < 3; i += 1) cur[i] += (goal[i] - cur[i]) * k;
    if (gapOf(goal) < SETTLE_GAP) cur = goal.slice();
    paint(goal);
    requestAnimationFrame(tick);
  }

02밝기 보정 섞기와 그냥 섞기를 나란히

왼쪽 버튼은 sRGB 값을 그대로 보간하고 오른쪽 버튼은 toLinear 로 밝기를 선형으로 되돌려 섞은 뒤 toGamma 로 다시 올린다. 진행도 50% 에서 그냥 섞은 색(#a6b9b1)의 상대 밝기는 약 0.459 로 양 끝(분홍 0.493·민트 0.514)보다 낮고, 보정한 색(#c1bcb1)은 약 0.505 로 두 끝 사이에 머문다. 02 항목은 누적면적 18.1%·강도 평균 48.3·움직인 프레임 21/23 이다.

밝기 보정 섞기와 그냥 섞기를 나란히
새 창에서 열기

02 · 밝기 보정 섞기와 그냥 섞기를 나란히 — 측정 누적면적 18.131% · 움직인 프레임 21/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

MIX_RATEtoLineartoGammamixLinear
  function toLinear(c) {
    var s = c / 255;
    return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
  }
  function toGamma(l) {
    var s = l <= 0.0031308 ? l * 12.92 : 1.055 * Math.pow(l, 1 / 2.4) - 0.055;
    return Math.max(0, Math.min(255, s * 255));
  }
  function mixRaw(a, b, t) { return a.map(function (v, i) { return v + (b[i] - v) * t; }); }
  function mixLinear(a, b, t) {
    return a.map(function (v, i) {
      var la = toLinear(v);
      return toGamma(la + (toLinear(b[i]) - la) * t);
    });
  }

03색 경계가 스프링으로 밀려가는 그라데이션

그라데이션 정지점 --stop 을 STIFFNESS 와 DAMPING 으로 정한 스프링에 넣고 1/120초 고정 간격으로 적분해, 20% 에서 목표 70% 로 가며 11.1 만큼 지나쳤다 돌아온다. 떼면 20% 아래로 반대 방향 오버슛을 하고 난 뒤 자리를 잡는다. 03 항목은 누적면적 13.7%·강도 평균 92.8·움직인 프레임 20/23 이다.

색 경계가 스프링으로 밀려가는 그라데이션
새 창에서 열기

03 · 색 경계가 스프링으로 밀려가는 그라데이션 — 측정 누적면적 13.651% · 움직인 프레임 20/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

STIFFNESSDAMPINGSTOP_RESTSTOP_HOVER
  function tick(ts) {
    if (t0 === null) t0 = ts;
    var now = ts - t0;
    var dt = lastTs === null ? 0.016 : Math.min(0.05, (ts - lastTs) / 1000);
    lastTs = ts;
    var g = goal(now);
    acc += dt;
    while (acc >= STEP) {
      vel += (STIFFNESS * (g - pos) - DAMPING * vel) * STEP;
      pos += vel * STEP;
      acc -= STEP;
    }
    paint();
    requestAnimationFrame(tick);
  }

04두 겹을 포개 그라데이션을 바꾸는 크로스페이드

왼쪽은 클래스를 갈아 끼워 진행도 0.5 에서 그라데이션이 통째로 바뀌는 컷이고, 오른쪽은 아래 겹 위에 다른 그라데이션 겹을 포개 그 겹의 opacity 만 FADE_RATE 비율로 옮겨 두 색 조합을 섞는다. 이 데모는 불투명도 값도 JS 가 계산하므로 겹을 포개 섞는 원리를 보이는 장면이다. 04 항목은 누적면적 17.3%·강도 평균 97.3·움직인 프레임 22/23 이다.

두 겹을 포개 그라데이션을 바꾸는 크로스페이드
새 창에서 열기

04 · 두 겹을 포개 그라데이션을 바꾸는 크로스페이드 — 측정 누적면적 17.253% · 움직인 프레임 22/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

FADE_RATESTART_MSON_MS
  function tick(ts) {
    if (t0 === null) t0 = ts;
    var now = ts - t0;
    var dt = lastTs === null ? 0.016 : Math.min(0.05, (ts - lastTs) / 1000);
    lastTs = ts;
    var g = goal(now);
    amount += (g - amount) * (1 - Math.exp(-dt * FADE_RATE));
    if (Math.abs(g - amount) < 0.004) amount = g;
    paint();
    requestAnimationFrame(tick);
  }

05각도가 포인터 쪽으로 돌아서는 그라데이션

버튼 중심에서 포인터까지의 방향을 atan2(dx, -dy) 로 각도로 바꿔 그라데이션 --ang 가 FOLLOW_RATE 비율로 따라가고, 포인터가 나가면 REST_ANGLE 인 135도로 돌아온다. 현재 각도와 목표의 차이를 ((g - a + 540) % 360) - 180 으로 접어 가까운 쪽으로 돌기 때문에 350도에서 10도로 가도 반대로 한 바퀴를 돌지 않는다. 05 항목은 누적면적 14.7%·강도 평균 132.5·움직인 프레임 23/23 이다.

각도가 포인터 쪽으로 천천히 돌아서는 그라데이션
새 창에서 열기

05 · 각도가 포인터 쪽으로 천천히 돌아서는 그라데이션 — 측정 누적면적 14.651% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

FOLLOW_RATEREST_ANGLEORBIT_SPANORBIT_MS
  function demoGoal(now) {
    if (now < START_MS) return REST_ANGLE;
    var c = (now - START_MS) % CYCLE_MS;
    if (c >= ORBIT_MS) return REST_ANGLE;
    return wrap(60 + (c / ORBIT_MS) * ORBIT_SPAN);
  }

  function tick(ts) {
    if (t0 === null) t0 = ts;
    var now = ts - t0;
    var dt = lastTs === null ? 0.016 : Math.min(0.05, (ts - lastTs) / 1000);
    lastTs = ts;
    var g = root.classList.contains('is-demo') ? demoGoal(now) : goalAngle;
    var diff = ((g - angle + 540) % 360) - 180;
    angle = wrap(angle + diff * (1 - Math.exp(-dt * FOLLOW_RATE)));
    paint();
    requestAnimationFrame(tick);
  }

06누르고 있는 동안 색상이 가속하며 도는 버튼

누르는 동안 ACCEL 만큼 회전 속도가 MAX_SPEED 까지 오르고, 떼면 exp(-FRICTION * dt) 비율로 줄어 멈춘 자리의 색상에 그대로 남는다. 포인터는 setPointerCapture 로, 키보드는 Space·Enter 의 비반복 keydown 부터 keyup 까지를 누름으로 쳐서 같은 경로를 탄다. 06 항목은 누적면적 16.0%·강도 평균 77.4·움직인 프레임 23/23 이다.

누르고 있는 동안 색상이 가속하며 도는 버튼
새 창에서 열기

06 · 누르고 있는 동안 색상이 가속하며 도는 버튼 — 측정 누적면적 15.999% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

MAX_SPEEDHUE_STARTHUE_STEPHOLD_MS
  function tick(ts) {
    if (t0 === null) t0 = ts;
    var now = ts - t0;
    var dt = lastTs === null ? 0.016 : Math.min(0.05, (ts - lastTs) / 1000);
    lastTs = ts;
    if (demoPressed(now) || pressed) {
      speed = Math.min(MAX_SPEED, speed + ACCEL * dt);
    } else {
      speed *= Math.exp(-FRICTION * dt);
      if (speed < 0.5) speed = 0;
    }
    hue = (hue + speed * dt) % 360;
    paint();
    requestAnimationFrame(tick);
  }

07바탕이 밝아지면 글자색이 뒤집히는 버튼

바탕이 움직이는 프레임마다 WCAG 식 상대 밝기를 재서 FLIP_THRESHOLD 를 넘으면 글자를 검정으로, 아니면 흰색으로 바꾼다. 흰색과 검정이 같은 대비를 내는 밝기는 √(1.05×0.05)−0.05 = 0.179 이고 그때 대비가 4.58:1 이며, 분홍에서 민트로 가는 경로 전체의 최저 대비는 4.61:1 이다. 07 항목은 누적면적 16.1%·강도 평균 82.1·움직인 프레임 23/23 이다.

바탕이 밝아지면 글자색이 뒤집히는 버튼
새 창에서 열기

07 · 바탕이 밝아지면 글자색이 뒤집히는 버튼 — 측정 누적면적 16.139% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

FLIP_THRESHOLDFILL_RATEluminance
  function channel(c) {
    var s = c / 255;
    return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
  }
  function luminance(rgb) {
    return 0.2126 * channel(rgb[0]) + 0.7152 * channel(rgb[1]) + 0.0722 * channel(rgb[2]);
  }
  function ratio(a, b) {
    var hi = Math.max(a, b);
    var lo = Math.min(a, b);
    return (hi + 0.05) / (lo + 0.05);
  }
  function paint() {
    var l = luminance(cur);
    var dark = l > FLIP_THRESHOLD;
    btn.style.background = toHex(cur);
    btn.style.color = toHex(dark ? textDark : textLight);
    lumEl.textContent = l.toFixed(2);
    ratioEl.textContent = ratio(l, dark ? lumDark : lumLight).toFixed(1);
  }

08기울어진 빛 띠가 색 위를 훑는 광택

hover 가 켜지는 순간마다 105도로 기울인 밝은 띠가 BAND_FROM 에서 BAND_TO 까지 700ms 동안 한 번 지나가고, 세기는 PEAK_GLOW * sin(π p) 로 올랐다 내려온다. 위치는 smoothstep 이라 양 끝에서 느려지고 스윕이 끝나면 세기가 0 으로 돌아가 원래 색만 남는다. 08 항목은 누적면적 13.6%·강도 평균 72.3·움직인 프레임 12/23 이다.

기울어진 빛 띠가 색 위를 훑는 광택
새 창에서 열기

08 · 기울어진 빛 띠가 색 위를 훑는 광택 — 측정 누적면적 13.553% · 움직인 프레임 12/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

SWEEP_MSBAND_FROMBAND_TOPEAK_GLOW
  function tick(ts) {
    if (t0 === null) t0 = ts;
    var now = ts - t0;
    var on = demoOn(now) || pointerIn || kbFocus;
    if (on && !wasOn) sweepAt = now;
    wasOn = on;
    var p = sweepAt < 0 ? 1 : Math.min(1, (now - sweepAt) / SWEEP_MS);
    var eased = p * p * (3 - 2 * p);
    if (p >= 1) paint(BAND_FROM, 0);
    else paint(BAND_FROM + (BAND_TO - BAND_FROM) * eased, PEAK_GLOW * Math.sin(Math.PI * p));
    requestAnimationFrame(tick);
  }

09바탕색을 따라 그림자 색이 번지는 버튼

진행도 p 하나로 바탕색·그림자 색·그림자 높이·번짐 반경을 함께 정하고, 그림자 색은 바탕색 각 채널에 SHADOW_DARKEN 을 곱한 값이다. 높이는 4px 에서 14px, 번짐은 10px 에서 28px 로 p 에 비례해 올라 색이 목표에 가까워질수록 버튼이 바닥에서 뜬다. 09 항목은 누적면적 23.9%·강도 평균 90.1·움직인 프레임 21/23 이다.

바탕색을 따라 그림자 색이 번지는 버튼
새 창에서 열기

09 · 바탕색을 따라 그림자 색이 번지는 버튼 — 측정 누적면적 23.888% · 움직인 프레임 21/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

SHADOW_DARKENSHADOW_ALPHALIFT_HOVERBLUR_HOVERGLOW_RATE
  function paint() {
    var fill = from.map(function (v, i) { return v + (to[i] - v) * p; });
    var shade = fill.map(function (v) { return v * SHADOW_DARKEN; });
    var lift = LIFT_REST + (LIFT_HOVER - LIFT_REST) * p;
    var blur = BLUR_REST + (BLUR_HOVER - BLUR_REST) * p;
    btn.style.background = toHex(fill);
    btn.style.boxShadow = '0 ' + lift.toFixed(1) + 'px ' + blur.toFixed(1) + 'px rgba(' +
      Math.round(shade[0]) + ', ' + Math.round(shade[1]) + ', ' + Math.round(shade[2]) + ', ' + SHADOW_ALPHA + ')';
    hexEl.textContent = toHex(shade);
    yEl.textContent = String(Math.round(lift));
  }

값이 장면을 바꾸는 곳 — 끌림 비율·스프링 세기·밝기 기준

세 상수가 색이 도착하는 속도와 흔들림, 글자가 읽히는 구간을 거의 다 정한다. 표의 수치는 아홉 항목을 각각 렌더해 23개 프레임 간격마다 잰 값이다.

항목 누적면적 % 강도 평균 움직인 프레임
01 기본 끌림 16.2% 114.6 22/23
02 밝기 보정 섞기 18.1% 48.3 21/23
03 스프링 경계 13.7% 92.8 20/23
04 겹 크로스페이드 17.3% 97.3 22/23
05 포인터 각도 14.7% 132.5 23/23
06 가속 색상 16.0% 77.4 23/23
07 글자 뒤집힘 16.1% 82.1 23/23
08 빛 띠 광택 13.6% 72.3 12/23
09 그림자 번짐 23.9% 90.1 21/23

누적면적이 10% 아래인 항목은 없고, 08 이 12/23 으로 낮은 것은 hover 한 번에 띠가 700ms 동안 한 번만 지나가고 그 뒤에는 멈추기 때문이다. 02 의 강도가 가장 낮은 것도 두 버튼의 색 차이가 크지 않은 한 쌍이라서 정상이다.

끌림 비율이 도착 속도를 정한다

01 의 PULL_RATE 7 은 시정수가 약 143ms 라서 색이 절반쯤은 금방 도착하고 끝이 길게 끌린다. 값을 올릴수록 도착이 빨라지지만 색 변화가 한눈에 읽히는 구간이 짧아진다.

스프링 세기가 오버슛을 정한다

03 은 STIFFNESS 170 에서 목표 70% 를 11.1 지나쳐 최고 81.1 까지 갔다가 약 0.76초 안에 자리를 잡는다. 같은 DAMPING 11 에서 세기를 400 으로 올리면 오버슛이 19.9 로 커지고, 50 으로 낮추면 0.8 만 넘는다.

밝기 기준이 읽히는 구간을 정한다

07 의 FLIP_THRESHOLD 는 흰색과 검정이 같은 대비를 내는 0.179 가 기준이다. 이 값에서 벗어날수록 글자가 뒤집히기 전에 한쪽 색 위에서 대비가 급히 떨어진다.

어디서 깨지는가 — 빠른 hover 반복·탁한 중간색·읽히지 않는 글자

빠른 hover 반복에서 오버슛이 겹친다

01·09 는 상태가 항상 현재 값에서 이어지므로 올렸다 내리기를 반복해도 끊기지 않는다. 03 만은 속도 vel 이 남은 채 다시 들어오면 오버슛이 겹쳐 처음보다 크게 튄다.

그냥 섞은 중간색은 양 끝보다 어두워진다

02 의 왼쪽 버튼은 중간에서 밝기가 양 끝 아래로 꺼지고, hover 도중 색이 탁해 보이는 것은 이 밝기 저하와 맞물린다. 두 색의 채도는 중간에서도 약 0.12 와 0.11 로 비슷하니, 보정의 효과는 선명함이 아니라 중간에서 밝기가 꺼지지 않는다는 데 있다.

토큰 잉크 글자는 중간 구간에서 4.5 에 못 미친다

07 은 처음에 사이트 토큰의 잉크색 글자를 썼더니 크로스오버 구간의 대비가 4.15~4.27:1 로 기준 4.5 에 못 미쳐, 순수 흰색과 검정으로 바꿨다. 기준값을 0.08 로 낮추면 최저 대비가 2.64:1 로, 0.30 으로 올리면 3.01:1 로 내려가 읽기 어려운 구간이 생긴다.

각도의 경계를 접지 않으면 반대로 돈다

05 에서 접기 식을 빼면 350도에서 10도로 가는 길에 20도가 아닌 340도를 거꾸로 돌아 그라데이션이 한 바퀴 휘돈다. 각도를 쓰는 보간에는 항상 이 접기를 같이 둔다.

코드 전체와 SCSS 를 직접 만져 보려면 압축 파일을 내려받아 비밀번호 82z8gdmt 으로 열면 되고, 아홉 폴더 각각에 데모 페이지와 스타일이 들어 있다.

변형 세 가지와 접근성

항목 상수 값 느낌
01 PULL_RATE 7 → 14 시정수가 약 143ms 에서 71ms 로 줄어 색이 거의 즉시 도착하고, 낮추면 끝이 길게 끌린다
03 STIFFNESS 170 → 400 경계가 목표를 11.1 이 아니라 19.9 만큼 지나쳤다 돌아오고, 50 이면 0.8 만 넘어 거의 흔들림 없이 멈춘다
07 FLIP_THRESHOLD 0.179 → 0.08 글자가 일찍 검정이 되어 대비가 최저 2.64:1 까지 떨어지고, 0.30 이면 3.01:1 까지 내려간다

모든 장면은 네이티브 button 이라 Tab 으로 닿고, 01·02·03·04·07·08·09 는 :focus-visible 일 때 hover 와 같은 목표로 움직이며 06 은 Space·Enter 로 누른다. 05 는 포인터 방향이 정보라 키보드 목표가 없고 글자와 3px 포커스 링만 유지한다. prefers-reduced-motion 이 reduce 이면 루프를 돌리지 않고 입력이 오는 순간 목표 값을 바로 칠한다. 그래서 01·02·03·04·07·09 는 최종 색으로 점프하고 05 는 포인터 방향 각도로 즉시 바뀌며 06 은 누를 때마다 60도씩 뛰고 08 은 hover 중 정지한 띠만 남는다. 색 변화는 장식이라 aria-live 를 쓰지 않았고, 읽어야 하는 정보인 글자 대비는 07 이 linear-gradient 위가 아니라 계산 쪽에서 지킨다.

css 버튼 색상 변경은 transition 한 줄로 충분한가?

색 한 쌍을 단순하게 바꾸는 버튼이라면 한 줄로 충분하다. 다만 그 줄은 중간 색의 밝기와 그라데이션, 글자 대비를 따로 챙기지 않으므로 02·04·07 처럼 그 틈이 보이는 화면에서만 계산을 얹으면 된다.

색 말고 다른 반응이 필요하면 이웃 편을 이어 읽자. 클릭한 뒤의 상태를 다루는 css 버튼 클릭 효과 9종 — 누른 다음이 진짜다와, 키프레임 기반 복붙 버튼 모음인 CSS 버튼 애니메이션 9종 — 복붙하면 되는 SCSS + React가 맞다.

css 버튼 색상 변경을 쓰기 전에 자주 묻는 질문

css 버튼 그라데이션은 transition 으로 움직일 수 있나요?

이 편의 그라데이션 장면은 transition 에 맡기지 않고 JS 가 계산한 숫자로 옮긴다. 04 는 겹을 포개 위 겹의 불투명도를 옮기고, 03 은 정지점 위치를 숫자로 움직이며, 05 는 각도를 숫자로 움직인다.

그라데이션 버튼의 hover 색은 어떻게 고르나요?

두 색의 상대 밝기가 비슷하면 중간이 어두워지기 쉬우므로 02 처럼 밝기 보정 섞기를 먼저 보고 고른다. 바탕이 크게 밝아지는 쌍이면 07 처럼 글자색도 계산하게 둔다.

hover 색 바꾸기를 다른 입력에도 쓸 수 있나요?

포인터가 아닌 입력은 목표 값만 바꾸면 되어서 06 은 누름, 05 는 포인터 방향을 입력으로 받는다. 어떤 입력이든 현재 값에서 목표로 옮기는 계산 자체는 01 과 같다.

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

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