Skip to content

fix(a11y): «동작 줄이기» 가 랜딩에도 닿는다 — 전역 모션 감소 리셋을 공용 CSS 로 · 무한 애니메이션 반복 1회 · 브라우저 타이밍 e2e (#1746 K15) - #1779

Merged
xzawed merged 1 commit into
mainfrom
fix/k15-reduced-motion
Oct 29, 2026

Conversation

@xzawed

@xzawed xzawed commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

pytest tests/unit → 8631 passed / 5 skipped

무엇을 고쳤나 (#1746 K15 — 모션 감소)

원장 수정 전 수정 후
P1-57 랜딩은 base.html 을 상속하지 않아 전역 모션 감소 리셋이 닿지 않았다 — «동작 줄이기» 를 켜도 전체화면 고정 그라데이션 meshShift(14초 무한 확대·회전) · 배지 점 pulse(무한) · 미리보기 줄 reviewReveal 이 그대로 돌았다 리셋을 base.html 인라인 <style> 에서 components.css 로 옮겼다 — 두 레이아웃이 모두 읽는 파일이다
(같은 리셋) 지속만 0.01ms 로 줄여, 무한 애니메이션은 0.01ms 주기로 계속 돌았다(프레임마다 다른 지점 → 깜빡임) animation-iteration-count: 1 을 함께 건다
P1-58 이 축의 유일한 관측이 "prefers-reduced-motion" in css 부분문자열(리포 인사이트 CSS 한 파일) e2e/test_reduced_motion.py 6건 — 브라우저가 계산한 document.getAnimations() 타이밍을 읽는다. 부분문자열 시험은 지웠다(통합 208 → 207)
(스크립트 스크롤) 리포 상세 페이지 넘김의 scrollIntoView({behavior:'smooth'}) 는 CSS 리셋이 닿지 않는다 matchMedia('(prefers-reduced-motion: reduce)') 면 'auto'
P2-66(부분) base.html 인라인 <style> 의 .skeleton + @keyframes shimmer(1.4초 무한) — 리포 어디에서도 안 쓰는 죽은 규칙 삭제

계기 (P1-58)

화면마다 «감소 안 함» 과 «감소» 를 둘 다 잰다.

  • 대조군: «감소 안 함» 에서 움직이는 애니메이션이 1건 이상이어야 한다(두 레이아웃 모두 무한 orb-drift 를 가진다) — 0건이면 계기가 눈먼 것과 구별되지 않으므로 red.
  • 판정: «감소» 에서 running 인 애니메이션 중 반복이 무한이거나 지속이 1ms 를 넘는 것 = 0.
  • 화면: 랜딩(anonymous_page) · /dashboard · 리포 상세 · 리포 인사이트 · 설정 · 분석 상세.

증거

역-뮤테이션 게이트

reverse-mutation-not-applicable: 이 PR 의 관측자는 전부 e2e(e2e/test_reduced_motion.py — 애니메이션 타이밍 6 · 페이지 넘김 스크롤 1)라 tests/ 만 돌리는 이 게이트 밖이다. 같은 되돌림을 e2e 로 돌려 red 를 확인했다(위 증거). tests/ 변경은 거짓 관측자였던 부분문자열 시험의 삭제뿐이고, base.html 쪽은 죽은 규칙·중복 리셋 삭제라 관측할 동작이 없다.

Grok claim-review

  • session: 3c24975c-2c74-4db0-906e-9403cc592b12
  • claim: reduce 에서 이 화면들의 CSS 애니메이션·트랜지션은 활성 지속 0.01ms 이하·반복 1회 이하다(지연은 남을 수 있음) — 다른 !important 선언·인라인 style·JS 인라인 transition·SMIL·영상 유무를 전제로 넣음
  • verdict: SURVIVES
  • session: 6c931223-76b7-4f05-bbc8-a0243f95954b
  • claim: 페이지 넘김 스크롤 시험이 초록이면 reduce 에서 스크롤은 클릭과 같은 동기 구간에서 끝났다 — reduce 가 smooth 로 스크롤하는데 두 단언이 다 통과하는 상태는 없다(전제: CSS scroll-behavior 0건 · 클릭 핸들러 동기 · 머리 위 내용 불변 · 2→1 로 문서가 길어짐 · 두 심음 실측값)
  • verdict: SURVIVES

사람이 볼 것

  1. OS 의 «동작 줄이기»(Windows: 설정 → 접근성 → 시각 효과 → 애니메이션 효과 끄기)를 켜고 랜딩을 열어, 배경 그라데이션과 배지 점이 멈춰 있는지.
  2. 같은 상태로 앱 화면 — 카드 등장·카운트업이 즉시 최종 상태로 보이는지(이전과 같아야 한다).
  3. 끈 상태 — 랜딩·앱 애니메이션이 이전과 똑같이 움직이는지(리셋은 reduce 에서만 켜진다).

스스로 판단한 것

  • 이 PR 은 처음부터 역-뮤테이션 게이트가 red 였다(되돌린 생산 파일 3 · 돈 시험은 부분문자열 시험을 지운 tests/integration/test_repo_insights_css.py 하나 → 21 passed). 머지 직전에 그것을 보고, 관측 시험이 없던 페이지 넘김 스크롤 분기에 e2e 를 붙인 뒤 위 면제 문구를 적었다(면제는 job summary 에 계수된다).
  • P2-66 «모션 감소 방어가 죽은 선택자에 배분됐다» 는 회고 당시 base.html 의 감소 규칙이 지금과 같은 전역 * 리셋 하나였고, 현재 감소 블록 6곳의 선택자도 전부 살아 있어 문장 그대로는 재현하지 못했다. 대신 fix(ui): 3개월 반 동안 «렌더된 적 없는» 분석 상세 CSS 361줄을 살린다 #1651 의 죽은-CSS 사냥이 훑지 않은 인라인 <style> 에서 실제로 죽은 무한 애니메이션(.skeleton)을 찾아 지웠다 — 원장에는 «부분» 으로 적는다.
  • 리셋을 랜딩에 «복사» 하지 않고 공용 파일로 «옮겼다» — 두 벌이면 한쪽만 고쳐지는 순간 갈라진다.

K15 남은 것

P1-61 · P2-57 · P2-59 · P2-60 · P2-64 · P2-65 · P2-70 · P2-74 (+ #1776 이 맡은 P1-59·P1-60·P2-67·P2-68·P2-69).

🤖 Generated with Claude Code

https://claude.ai/code/session_01R4jYRzichV75XnYLSEFguX

@xzawed

xzawed commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

⚠️ AI 리뷰가 완전 검증되지 않음 — 기본값이 적용됐습니다(비활성/API 키 없음/빈 diff). AI 배점은 측정값이 아니므로 총점을 부분 점수로 보세요.
ℹ️ 정적분석이 수행되지 않은 언어 포함: css — 이 배포에서 해당 언어를 검사할 분석기가 실행되지 않아(분석기 미등록 또는 바이너리 미조달) 코드품질·보안 점수가 검사 없이 만점 처리됩니다. "깨끗함" 이 아니라 "검사 안 함" 입니다 — AI 리뷰와 수동 검토로 보완하세요.
ℹ️ 범용 검사기만 본 언어 포함: html — 이 배포에서 해당 언어의 전담 분석기가 하나도 실행되지 않아, 다언어 범용 분석기 하나에만 기대었습니다. 그 규칙 밀도는 언어마다 편차가 큽니다 — 여기서의 만점은 "깨끗함" 이 아니라 "거의 검사 안 됨" 입니다 — AI 리뷰와 수동 검토로 보완하세요.

🔵 SCAManager 분석 결과

총점: 84/100 (등급 B)

점수 상세

항목 점수 만점
커밋 메시지 13 15
코드 품질 22 25
보안 18 20
구현 방향성 (AI) 21 25
테스트 10 15

정적 분석 이슈 (상위 10건)

  • [flake8] line break before binary operator (e2e/test_reduced_motion.py:38)
  • [flake8] line break before binary operator (e2e/test_reduced_motion.py:57)
  • [semgrep] Manually-created forms in django templates should specify a csrf_token to prevent CSRF attacks. (src/templates/base.html:724)
  • [pylint] Import outside toplevel (re) (tests/integration/test_repo_insights_css.py:55)

@xzawed
xzawed force-pushed the fix/k15-reduced-motion branch from 0634b92 to f85163b Compare October 28, 2026 23:33
@xzawed

xzawed commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

⚠️ AI 리뷰가 완전 검증되지 않음 — 기본값이 적용됐습니다(비활성/API 키 없음/빈 diff). AI 배점은 측정값이 아니므로 총점을 부분 점수로 보세요.
ℹ️ 정적분석이 수행되지 않은 언어 포함: css — 이 배포에서 해당 언어를 검사할 분석기가 실행되지 않아(분석기 미등록 또는 바이너리 미조달) 코드품질·보안 점수가 검사 없이 만점 처리됩니다. "깨끗함" 이 아니라 "검사 안 함" 입니다 — AI 리뷰와 수동 검토로 보완하세요.
ℹ️ 범용 검사기만 본 언어 포함: html — 이 배포에서 해당 언어의 전담 분석기가 하나도 실행되지 않아, 다언어 범용 분석기 하나에만 기대었습니다. 그 규칙 밀도는 언어마다 편차가 큽니다 — 여기서의 만점은 "깨끗함" 이 아니라 "거의 검사 안 됨" 입니다 — AI 리뷰와 수동 검토로 보완하세요.

🔵 SCAManager 분석 결과

총점: 84/100 (등급 B)

점수 상세

항목 점수 만점
커밋 메시지 13 15
코드 품질 22 25
보안 18 20
구현 방향성 (AI) 21 25
테스트 10 15

정적 분석 이슈 (상위 10건)

  • [flake8] line break before binary operator (e2e/test_reduced_motion.py:38)
  • [flake8] line break before binary operator (e2e/test_reduced_motion.py:57)
  • [semgrep] Manually-created forms in django templates should specify a csrf_token to prevent CSRF attacks. (src/templates/base.html:724)
  • [pylint] Import outside toplevel (re) (tests/integration/test_repo_insights_css.py:55)

…1회 · 브라우저 타이밍 e2e (#1746 K15)

- 리셋을 base.html 인라인에서 components.css 로(랜딩은 base 를 상속하지 않아 meshShift·pulse 가 계속 돌았다)
- animation-iteration-count: 1 — 지속만 줄이면 무한 애니메이션이 0.01ms 주기로 계속 돈다
- e2e/test_reduced_motion.py 7건: getAnimations() 타이밍 6 + «감소 안 함» 대조군, 페이지 넘김 스크롤 1(클릭과 같은 동기 구간에서 읽는다). 부분문자열 시험 삭제
- 페이지 넘김 smooth 스크롤도 감소를 따른다 · 죽은 .skeleton(무한 shimmer) 삭제
- e2e 435 → 442 · 통합 208 → 207

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R4jYRzichV75XnYLSEFguX
@xzawed
xzawed force-pushed the fix/k15-reduced-motion branch from f85163b to 047b275 Compare October 29, 2026 00:17
@xzawed

xzawed commented Oct 29, 2026

Copy link
Copy Markdown
Owner Author

⚠️ AI 리뷰가 완전 검증되지 않음 — 기본값이 적용됐습니다(비활성/API 키 없음/빈 diff). AI 배점은 측정값이 아니므로 총점을 부분 점수로 보세요.
ℹ️ 정적분석이 수행되지 않은 언어 포함: css — 이 배포에서 해당 언어를 검사할 분석기가 실행되지 않아(분석기 미등록 또는 바이너리 미조달) 코드품질·보안 점수가 검사 없이 만점 처리됩니다. "깨끗함" 이 아니라 "검사 안 함" 입니다 — AI 리뷰와 수동 검토로 보완하세요.
ℹ️ 범용 검사기만 본 언어 포함: html — 이 배포에서 해당 언어의 전담 분석기가 하나도 실행되지 않아, 다언어 범용 분석기 하나에만 기대었습니다. 그 규칙 밀도는 언어마다 편차가 큽니다 — 여기서의 만점은 "깨끗함" 이 아니라 "거의 검사 안 됨" 입니다 — AI 리뷰와 수동 검토로 보완하세요.

🔵 SCAManager 분석 결과

총점: 84/100 (등급 B)

점수 상세

항목 점수 만점
커밋 메시지 13 15
코드 품질 22 25
보안 18 20
구현 방향성 (AI) 21 25
테스트 10 15

정적 분석 이슈 (상위 10건)

  • [flake8] line break before binary operator (e2e/test_reduced_motion.py:38)
  • [flake8] line break before binary operator (e2e/test_reduced_motion.py:57)
  • [semgrep] Manually-created forms in django templates should specify a csrf_token to prevent CSRF attacks. (src/templates/base.html:724)
  • [pylint] Import outside toplevel (re) (tests/integration/test_repo_insights_css.py:55)

@sonarqubecloud

Copy link
Copy Markdown

@codecov

codecov Bot commented Oct 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@xzawed
xzawed merged commit 833b0f2 into main Oct 29, 2026
15 checks passed
@xzawed
xzawed deleted the fix/k15-reduced-motion branch October 29, 2026 00:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant