Limit competitor substitution to brand-differentiation claims, add impact-scoped render measurement guidance to audit-gate, and correct motion, Range, and font-check wording found during review.
239 lines
22 KiB
Markdown
239 lines
22 KiB
Markdown
# preflight — 출시 전 감사
|
||
|
||
5단계에서 읽는다. **자기 결과물을 남의 것처럼 본다.** 통과 못 한 항목은 4단계로 돌아가 고친다.
|
||
|
||
슬롭 지문 검출과 자가 채점표는 `references/antipatterns.md` 에 있다. 이 문서는 **그 외 전부**를 다룬다.
|
||
|
||
---
|
||
|
||
## 0. 먼저 기계로 검사한다
|
||
|
||
**무엇에 돌리는가부터 정해라.**
|
||
- 정적 HTML/CSS 프로젝트 → 소스 그대로
|
||
- **React·Vue·Astro 등 프레임워크 프로젝트 → 프로덕션 빌드 결과에 돌린다.** 소스만 보면 렌더된 DOM 이 없어 대비·가로 스크롤·LCP 를 잴 수 없다. `pnpm build && pnpm preview` 로 띄우고 그 URL 을 검사해라
|
||
- **소스만 보고 "측정 불가"로 남기지 마라.** 미측정은 통과가 아니다
|
||
|
||
grep 검사는 **주석과 문자열을 제외**해라. "100vh 금지"라고 쓴 주석이 게이트 #9 에 걸리는 오탐이 실제로 나왔다.
|
||
|
||
사람 눈보다 정확하고 빠르다. 셋 다 돌려라.
|
||
|
||
### A. 이펙트 전부 끄기
|
||
```css
|
||
/* 임시로 주입해서 확인한다 */
|
||
*, *::before, *::after {
|
||
filter: none !important;
|
||
backdrop-filter: none !important;
|
||
animation: none !important;
|
||
transition: none !important;
|
||
transform: none !important;
|
||
}
|
||
canvas { display: none !important; }
|
||
```
|
||
이 상태에서 **페이지가 여전히 읽히고 구조가 살아 있어야 한다.** 무너지면 이펙트가 구조를 대신하고 있는 것이다. 4-1로 돌아가라.
|
||
|
||
### B. 스타일 후보 grep
|
||
`references/antipatterns.md`의 grep 목록을 소스에 돌려 보라 CTA, 전체 대문자 헤드라인, 번호 매긴 단계 같은 반복 후보를 찾는다. 검출은 실패가 아니다. 프로젝트 계약·브리프·실제 렌더를 대조해 결정을 기록한다.
|
||
|
||
### C. 카피 경쟁사 치환
|
||
브랜드가 특별하다고 주장하는 문구에만 제품·회사 이름을 경쟁사 이름으로 바꿔 읽는 **진단 질문**을 쓴다. 다른 업체에도 그대로 성립하면 근거와 구체성을 재검토한다. 수업·가격·대상·위치·FAQ·CTA 같은 안내는 치환만으로 실패시키지 않는다. 독자의 실제 질문에 대한 구체적 답, 검증 가능한 사실, 자연스러운 업종 표현을 먼저 확인한다.
|
||
|
||
낯선 업종이나 추상 표현의 용법이 불확실할 때만 공식 실제 사례를 소규모로 조사해 용어를 참고한다. 그 사례의 주장·실적·후기를 가져오지 않으며, 현재 프로젝트의 사실로 바꾸어 말하지 않는다.
|
||
|
||
### D. 죽은 코드·토큰 위생 (design-gate 내장 검사)
|
||
- CSS 클래스가 HTML·JS 어디에도 등장하지 않으면 죽은 것이다. 컴포넌트를 없앨 때 HTML·CSS·JS 를 **삼위일체로** 지웠는지 대조한다(동적 클래스 `is-${type}`·`seg-${n}` 처럼 조립되는 접두사는 게이트 설정의 `deadCssIgnore` 로 제외한다)
|
||
- 토큰 파일이 있는데 다른 CSS 파일에 색 리터럴(hex·rgb)이 남아 있으면 실패다. 반지름 리터럴도 마찬가지 — 눈 검사로는 절대 전부 못 잡는다(실측: 8건의 상수색이 눈 검사를 통과했다)
|
||
- `theme-color` 메타가 실제 배경색과 다르면 **낡은 토큰**이다. 프리셋 전환에서 브랜드 표면(theme-color·파비콘·og:image)이 누락됐다는 뜻이다
|
||
|
||
### E. 왼쪽 인셋 리듬 (모바일)
|
||
오버플로 검사는 오른쪽만 본다 — **왼쪽이 붙어 깨지는 결함은 통과한다**(실측: 제목 16px·앱바·카드 24px 혼재가 게이트를 통과해 사용자 보고로 나왔다). 모바일 폭(320·390)에서:
|
||
- 화면의 모든 보이는 텍스트 시작점 ≥ 12px
|
||
- 헤더 텍스트·화면 제목·카드 텍스트가 **같은 축**(±10px)
|
||
- 측정은 전폭 컨테이너의 보더박스가 아니라 **텍스트 시작점**, `display:none` 요소(rect=0)는 제외하고
|
||
|
||
---
|
||
|
||
## 1. 접근성 — 타협 없음
|
||
|
||
| 항목 | 확인 방법 | 기준 |
|
||
|---|---|---|
|
||
| 키보드 도달 | Tab 만으로 순회 | 모든 인터랙티브 요소에 도달, 순서가 시각 순서와 일치 |
|
||
| 포커스 표시 | Tab 하며 눈으로 | 항상 보인다. `outline: none` 만 있고 대체가 없으면 실패 |
|
||
| 대비 | 측정 도구 (아래 주의) | 본문 4.5:1, 큰 글자·UI 3:1 |
|
||
| 이미지 대체텍스트 | 소스 확인 | 의미 있는 이미지에 alt, 장식은 `alt=""` |
|
||
| 폼 레이블 | 소스 확인 | 모든 입력에 연결된 `<label>`. placeholder 는 레이블이 아니다 |
|
||
| 제목 구조 | 개요 확인 | h1 하나, 건너뛰지 않음 |
|
||
| 모션 감소 | `prefers-reduced-motion` 켜고 확인 | **전부 끄는 게 정답이 아니다** — 위치 이동·시차·자동재생을 죽이고, 페이드·상태 변화는 남긴다 |
|
||
| 자동재생 | 확인 | 5초 이상 반복되는 애니메이션에는 정지 수단이 있다 |
|
||
| 캔버스/WebGL 실패 | JS 끄고 확인 | 콘텐츠가 여전히 보인다 |
|
||
|
||
> **대비를 스크립트로 잴 때 — 반투명 배경을 불투명으로 계산하지 마라.**
|
||
> `getComputedStyle(el).backgroundColor` 로 조상을 거슬러 올라가며 "투명이 아닌 첫 값"을 배경으로 쓰면,
|
||
> `rgb(255 255 255 / 0.085)` 같은 유리 틴트를 **순백**으로 취급한다. 흰 글자가 1.15:1 로 나온다.
|
||
> 알파가 1 미만인 층은 계속 쌓고, **아래에서 위로 합성**한 뒤에 재라:
|
||
>
|
||
> ```js
|
||
> // 알파 < 1 이면 멈추지 말고 계속 쌓는다
|
||
> const stack = []; let e = el;
|
||
> while (e && e !== document.documentElement) {
|
||
> const p = parse(getComputedStyle(e).backgroundColor);
|
||
> if (p && p[3] > 0) { stack.push(p); if (p[3] >= 1) break; }
|
||
> e = e.parentElement;
|
||
> }
|
||
> let [r, g, b] = rootBg;
|
||
> for (let i = stack.length - 1; i >= 0; i--) {
|
||
> const [sr, sg, sb, sa] = stack[i];
|
||
> r = sr*sa + r*(1-sa); g = sg*sa + g*(1-sa); b = sb*sa + b*(1-sa);
|
||
> }
|
||
> ```
|
||
>
|
||
> 유리·오버레이·틴트를 쓰는 페이지에서는 이 차이가 **통과와 실패를 뒤집는다.**
|
||
> **검사 도구가 틀리면 통과도 실패도 의미가 없다.** 실패가 나오면 값을 고치기 전에 측정을 먼저 의심해라.
|
||
|
||
**스크린리더를 실제로 켜볼 수 없다면** 최소한 소스의 읽기 순서를 확인해라. `order`·`position: absolute` 로 시각 순서를 바꿨다면 읽기 순서가 어긋난다.
|
||
|
||
---
|
||
|
||
## 2. 성능 — 3단계에서 정한 예산과 대조
|
||
|
||
**예산 값은 `tokens.md` §5 를 보라. 여기서 다시 적지 않는다** — 두 곳에 적으면 갈라진다.
|
||
이 문서가 하는 일은 **실측을 채우는 것**이다.
|
||
|
||
| 항목 | 실측 | 판정 |
|
||
|---|---|---|
|
||
| 히어로까지 JS (gzip) | | |
|
||
| WebGL/3D 추가분 | | |
|
||
| 총 전송량 (첫 화면) | | |
|
||
| 첫 인터랙션 (모바일 4G) | | |
|
||
| LCP | | |
|
||
| CLS | | |
|
||
| 폰트 파일 수 | | |
|
||
|
||
**측정하지 않았으면 통과가 아니다.** 예산을 넘겼다면 둘 중 하나다: 이펙트를 빼거나, 예산을 올린 이유를 명시하거나.
|
||
|
||
### 폰트 (`typography.md` §8 이 전체 목록)
|
||
|
||
- [ ] 웹폰트를 쓰면 실제 교체 시점의 레이아웃을 측정하고, 폴백 메트릭·`font-display` 전략을 선택했다. 특정 전략만으로 CLS 유무를 단정하지 않는다
|
||
- [ ] 폰트를 preload했다면 첫 화면에서 실제로 쓰이고 요청에 맞는 `crossorigin`이 있다
|
||
- [ ] 수치 비교가 필요한 곳의 숫자 정렬을 확인했다. `tabular-nums`는 해당 서체의 지원과 과업에 맞춰 선택한다
|
||
- [ ] 한글 글꼴과 시스템 폴백을 실제로 확인했다. 웹폰트를 전송하는 경우 서브셋·전송량·글리프 범위를 검토했다
|
||
- [ ] 웹폰트를 임베딩하면 라이선스를 확인해 `design.md`에 적었다
|
||
- [ ] 웹폰트를 쓰면 **폰트를 못 받은 상태로 열어봤다.** 그 상태로도 읽힌다
|
||
|
||
### 자주 걸리는 것
|
||
- 전송하는 폰트의 크기·글리프 범위 미측정. 한글 웹폰트는 필요한 범위와 라이선스에 맞춰 서브셋을 검토한다
|
||
- 첫 화면 밖 이미지에 `loading="lazy"` 누락
|
||
- 3D/WebGL을 초기 번들에 포함 (뷰포트 진입 시 동적 import 해야 한다)
|
||
- 애니메이션이 `top`/`left`/`width` 를 건드림 → `transform`·`opacity`로 가능한지 먼저 검토하고, 유지한다면 비용·CLS·입력 간섭·감소 모션을 측정해 예산과 대조한다
|
||
- `will-change` 남발 → 레이어가 늘어 오히려 느려진다
|
||
|
||
---
|
||
|
||
## 3. 반응형
|
||
|
||
- [ ] 프로젝트가 채택한 회귀 매트릭스에서 가로 스크롤 없음. 이 저장소의 기본 매트릭스는 **320·390·768·1440·1920·2560px**이며, 지원 기기·브리프가 다르면 그 계약을 바꾸고 이유를 기록한다
|
||
- [ ] 변경 영향에 따라 프로젝트가 채택한 뷰의 너비×높이, 짧은 화면, 긴 세로 흐름, 뷰포트 종횡비·피사체 보존·실제 clipping, 글자 확대를 추가로 검사한다. 크롬·모달·긴 폼·고정 CTA는 짧은 화면의 가시 영역과 scroll owner를, 목록·본문·이미지는 긴 세로 흐름과 피사체 보존을, 글꼴·카피·컨트롤은 지원 확대 상태를 잰다. 모션 상태와 clipping의 상세 계약은 [렌더 측정 계약](audit-gate.md)을 따른다
|
||
- [ ] **크롬(탑바·앱바·툴바)에 컨트롤을 더했다면 그 줄의 최소폭 합을 가장 좁은 폭에서 다시 잰다** — 버튼 하나가 320px를 뚫는 사고가 반복된다(실측: 인쇄 버튼 1개로 +18px). 줄이 넘으면 감싸기(2행 랩)가 기본 수습이다
|
||
- [ ] 프로젝트 회귀 매트릭스의 각 폭에서 실제 브라우저 렌더를 잰다. 기본 매트릭스(320·390·768·1440·1920·2560px)는 저장소의 회귀 범위이며 WCAG의 보편 폭 기준은 아니다. 최소 폭의 오버플로와 wide 화면의 카피 측정폭·제목 칼럼을 함께 확인한다
|
||
- [ ] WCAG 200% 확대 또는 운영체제의 실제 글꼴 확대가 지원 범위라면 실제 브라우저·기기에서 별도 검증한다. gate의 font-scale 행렬은 회귀 신호이며 px 고정 폰트의 OS 확대를 대체하지 않는다
|
||
- [ ] 1920px 이상에서는 본문 측정폭을 유지하고, 표·도면·작업대처럼 정보 밀도가 필요한 표면만 별도의 `--container-wide`로 넓힌다. 같은 `max-width`를 전부 풀어 넓은 화면을 빈 종이로 만들지 않는다
|
||
- [ ] 분할 히어로는 1920·2560에서 `hero / copy / media / 다음 정보 레일` rect를 기록했다. 사진의 최대 폭과 카피의 최소 폭을 페이지 토큰으로 정하고, 단지 viewport를 반으로 나눈 `1fr 1fr`가 사진을 무제한 키우지 않는지 확인한다
|
||
- [ ] hero 검증만으로 text-media 분할 검증을 끝내지 않는다. 과정·추천·가맹처럼 DOM/여백 규칙이 다른 모든 분할 표면에서 rail·copy·media·제목의 실제 rect와 줄 수를 기록한다. wide override가 있다면 기존 `padding-left/right: calc(100vw …)`를 **양쪽 모두** 재설정했는지, 상위 `max-width`의 선택자 우선순위가 named stage를 다시 줄이지 않는지 확인한다
|
||
- [ ] 중간 뷰포트(768~1024px)에서 레이아웃이 깨지지 않음 — **가장 자주 빠뜨리는 구간**
|
||
- [ ] 터치 타깃: **버튼·아이콘·카드 등 독립 컨트롤은 44×44px 이상**(Apple/Google 권고)
|
||
- [ ] 터치 타깃: **본문 안 인라인 텍스트 링크는 24×24px 이상**(WCAG 2.5.8 AA). 여기에 44 를 요구하면 정상적인 내비 링크가 오탐된다
|
||
- [ ] **컨트롤의 내용 여백**: 버튼 라벨·입력값·select 표시·표 셀의 실제 렌더 글자가 테두리에 닿지 않는다. 이 저장소의 실렌더 기본값은 좌우 **8 CSS px** 이상이다. 이는 WCAG 적합성 수치가 아니라 검증 가능한 시각 품질 기본값이며, 아이콘 전용·체크박스·의도적인 데이터 정렬은 별도 근거를 적는다
|
||
- [ ] **폼 기하**: 연결된 label/name/autocomplete를 확인한 뒤 실제 렌더 rect로 입력끼리 겹치지 않는지 잰다. 좁은 폭에서는 필드를 세로로 쌓고, label·입력·오류 문장이 서로의 클릭/읽기 영역을 침범하지 않게 한다
|
||
- [ ] **표와 표처럼 보이는 flex/grid**: 데이터 관계에는 `th`/`td`와 `scope`를 쓰고, 모든 가시 셀에 좌우 읽기 여백을 둔다. 좁은 폭에서 스크롤·카드화로 형식이 바뀌어도 헤더-값 관계가 남아야 한다
|
||
- [ ] 호버로만 접근되는 기능 없음
|
||
- [ ] 긴 단어/URL이 넘치지 않음 (`overflow-wrap: anywhere`)
|
||
- [ ] 가로 모드에서 첫 화면이 잠기지 않음
|
||
|
||
> 근거: [W3C WCAG 2.5.8 Target Size](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum) (최소 24 CSS px/간격 예외), [Apple HIG Layout](https://developer.apple.com/design/human-interface-guidelines/layout) (읽기 폭·음의 공간·다양한 화면 크기), [Apple HIG Text Fields](https://developer.apple.com/design/human-interface-guidelines/text-fields?changes=_7) (일관된 필드 폭·간격·세로 배치), [W3C Tables Tutorial](https://www.w3.org/WAI/tutorials/tables/tips/) (반응형에서도 데이터 관계 보존), [NN/g Form White Space](https://www.nngroup.com/articles/form-design-white-space/) (인접 요소의 간격이 관계를 전달함). 조사일 2026-08-30.
|
||
|
||
---
|
||
|
||
## 4. 콘텐츠
|
||
|
||
- [ ] 히어로가 **무엇인지** 말한다. 형용사만 있고 명사가 없으면 실패
|
||
- [ ] 로렘입숨이 남아 있지 않다
|
||
- [ ] 실제 콘텐츠 길이로 테스트했다 (짧은 제목만으로 맞춘 레이아웃은 긴 제목에서 깨진다)
|
||
- [ ] 빈 상태·오류 상태·로딩 상태가 있다
|
||
- [ ] 링크가 어디로 가는지 텍스트만 보고 알 수 있다 ("여기를 클릭" 금지)
|
||
- [ ] 이미지가 없거나 실패했을 때 레이아웃이 무너지지 않는다(`aspect-ratio` 지정)
|
||
|
||
---
|
||
|
||
## 4-1. 상태 완결성 — 동작하는 화면의 빈틈
|
||
|
||
정적 마케팅 페이지에는 없는 검사다. **입력·파괴·열림**이 있는 화면(폼·콘솔·앱)은 네 가지를 갖춰야 프로덕션이다. 실제로 조작해 본다 — 눈으로 봐서는 안 보인다(실측: 범위 밖 101점이 조용히 평균에 반영되고 있었다).
|
||
|
||
- [ ] **수치 입력에는 범위가 있다** — 범위 밖 값은 인라인 오류로 이유를 말하고 제출을 막는다(`aria-invalid`). 스트랩 검증만 믿지 마라: `type="number"` 의 `min`/`max` 는 직접 입력을 막지 못한다
|
||
- [ ] **판정은 순수 함수다** — 가능/불가+사유의 판정 로직은 UI 핸들러에 두지 않고 `calc.js` 같은 모듈로 추출해 단위 테스트(L1)가 같은 판정을 공유하게 한다. UI 는 판정 결과를 문장으로 번역만 한다. 실행취소의 재심사도 같은 함수를 쓴다
|
||
- [ ] **파괴적 행동에는 되돌림이 있다** — 삭제·취소는 실행취소 또는 확인. 되돌리기가 확인보다 낫다(흐름이 끊기지 않는다). 재신청·복원은 원래 판정 함수로 다시 심사한다 — 사이에 끼어든 다른 변화가 있으면 정당하게 막혀야 한다
|
||
- [ ] **열리는 것은 Esc 로 닫힌다** — 모달만이 아니다. 드롭다운·팝오버·알림 메뉴도. 닫힐 때 포커스는 연 요소로 돌아간다
|
||
- [ ] native `<dialog>` 또는 동등 모달은 전역 reset 뒤에도 `position: fixed; inset: 0; margin: auto`와 viewport 상한/내부 scroll owner를 가진다. 390·1440·2560에서 중심점, 화면 안 rect, 배경 scroll lock을 실제로 단언한다. W3C의 modal dialog 키보드·포커스·닫기 계약을 따른다: [WAI-ARIA APG](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/), [MDN dialog](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog)
|
||
- [ ] **로딩 상태는 실제 비동기에만** — 동기 인라인 데이터에 스켈레톤을 붙이는 건 저장을 흉내내는 것이다. 없는 지연을 만들지 마라
|
||
|
||
---
|
||
|
||
## 4-2. 진실 완결성 — 가상·예시·AI·규제 화면
|
||
|
||
가상 브랜드·예시 데이터·AI 분석·규제 주제를 실제 서비스처럼 보이게 만든 화면에만 돈다. 전역 데모 띠 하나로 끝내지 않는다. 상세 설계는 `trustworthy-showcases.md`.
|
||
|
||
- [ ] 모든 숫자·주소·상태·추천이 **사실 / 예시 / 추론 / 미정** 중 하나이고 `USER_SELF_REPORT / VERIFIED_SOURCE / SYSTEM_STATE / SYNTHETIC_FIXTURE` 출처 계층이 추적된다. 자기보고 값 자체를 검증 사실로 승격하지 않았다
|
||
- [ ] `예시 가격`, `거래 불가`, `실제 접수 아님`, `연출 이미지` 라벨이 오해가 생기는 범위 가까이에 있다. 같은 상태·출처·행동 가능성을 공유하는 자식은 가장 가까운 공통 부모가 한 번 소유하고, 다른 자식만 예외 라벨을 가진다
|
||
- [ ] 검증하지 않은 수익·가맹비·매장 수·등록번호·연락처를 만들지 않았다. 모르면 `미정`이다
|
||
- [ ] AI 결과에 입력 조건·출처가 붙은 입력/검증 사실·추론·불확실/누락·수정·사람 검토가 있고, 입력을 바꾸면 결과와 근거가 함께 바뀐다. 모델 출력 내용을 `SYSTEM_STATE` 사실로 두지 않았다
|
||
- [ ] 진단·개인화 추천·예약·전송·거래·게시·내보내기 등 실제 규제 행동은 행동별 필수 검증이 없을 때 **실패 폐쇄형**이며, 미등록 행동은 기본 거절되고 막힌 이유가 화면에 보인다
|
||
- [ ] 민감 입력과 파생값의 영속 저장·쿠키·분석 이벤트 포함·네트워크 전송 경계를 E2E로 검증했다
|
||
- [ ] 공개 화면은 사용자 해석·제한·다음 행동을, 관리자는 내부 원장·검증 이벤트·채널 판정·감사 로그를 소유한다. 사용자 행동에 영향을 주는 제한을 관리자에만 숨기지 않았다
|
||
- [ ] 지도·차트·도식의 같은 정보가 DOM 목록·표·설명으로도 제공되고 데이터 원천이 하나다
|
||
- [ ] 생성 이미지는 가격·주소·점수의 증거로 쓰이지 않으며, 프로젝트가 채택한 모바일 뷰와 종횡비에서 핵심 피사체가 첫 화면의 의도와 맞는다
|
||
- [ ] URL별 390·1440 기본 화면과 핵심 입력/오류/모달 상태 캡처를 실제로 열어 보고 시각 PASS/RED를 따로 기록했다
|
||
|
||
## 4-3. 썸네일·OG 캡처 — 움직이는 화면을 대표하지 않는다
|
||
|
||
썸네일은 '페이지가 열렸다'는 증거가 아니라 사람들이 처음 보는 **정지된 브랜드 표면**이다. 로딩 중인 폰트, 이미지 디코드 전 프레임, 입장 모션 중간, 다음 WebGL 프레임을 파일로 남기면 정상 사이트도 카드에서 망가져 보인다.
|
||
|
||
- [ ] `file://` 즉시 캡처 대신 실제 배포와 같은 상대 URL을 해석하는 로컬 HTTP 서버에서 고정 viewport로 연다. 로컬 4xx, runtime error, `naturalWidth === 0` 이미지는 캡처 성공이 아니라 실패다
|
||
- [ ] `document.fonts.ready`와 모든 가시 이미지의 `decode()`를 기다린 뒤, 페이지별로 정한 **bounded settle 시간**을 지난다. `document.fonts.ready`는 사용 중인 폰트의 로드와 레이아웃 작업이 끝날 때 이행한다
|
||
- [ ] 캡처 환경은 `prefers-reduced-motion: reduce`를 에뮬레이션하고, 영상·오디오는 정지하며 CSS/WAAPI 애니메이션과 rAF 기반 canvas를 **정착한 한 프레임**에 멈춘다. `animation: none`으로 초기 상태를 되돌려 빈 화면을 만들지 말고, 실제로 완성된 프레임을 pause/finish 한다
|
||
- [ ] 기본 컷·모달/결과 컷·OG 모두 같은 계약으로 찍고, 파일의 규격·0바이트·해시 중복을 검사한 뒤 적어도 움직임이 있던 대표 컷을 눈으로 연다. 생성 이미지가 있으면 기존 진실 라벨 계약도 그대로 보존한다
|
||
|
||
> 근거: [MDN `Document.fonts`](https://developer.mozilla.org/en-US/docs/Web/API/Document/fonts) (`ready`는 사용 중인 폰트의 로드와 레이아웃 완료 뒤 이행), [MDN `HTMLImageElement.decode()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode), [MDN `prefers-reduced-motion`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) (불필요한 모션을 줄이거나 대체하는 사용자 선호). 조사일 2026-08-30.
|
||
|
||
---
|
||
|
||
## 5. 디자인 자체
|
||
|
||
기계로 못 잡는 부분이다. **정직하게 답해라.**
|
||
|
||
첫인상·실제 과업 행동·접근성 적합성·전문가 시각 검토가 필요한 경우, [design foundations의 평가 절차](design-foundations.md)를 읽고 각 결과를 분리해 기록한다.
|
||
|
||
1. **이 사이트를 다른 회사의 것으로 바꿔도 그대로 쓸 수 있는가?** → 그렇다면 브리프에 맞춘 것이 없다
|
||
2. **2단계에서 정한 한 문장 컨셉이 화면에서 보이는가?** → 안 보이면 컨셉이 문서에만 있는 것이다
|
||
3. **감수하기로 한 리스크가 실제로 들어갔는가?** → 구현 중에 안전한 쪽으로 후퇴하지 않았는지
|
||
4. **사용한 레퍼런스의 원칙이 브리프와 렌더 결과에 맞게 번역됐는가?** → 슬롯 수나 업종 차이 자체로 판단하지 않는다
|
||
5. **강조색·radius·정렬·반복이 프로젝트 토큰과 과업에 맞는가?**
|
||
6. **여백이 의도적인가, 남은 것인가?**
|
||
|
||
---
|
||
|
||
## 6. 최종 게이트
|
||
|
||
전부 통과해야 끝난다.
|
||
|
||
- [ ] 0장 기계 검사 4종 통과
|
||
- [ ] 접근성 표 전 항목 통과
|
||
- [ ] 성능 예산 내 (또는 초과 이유 명시)
|
||
- [ ] 반응형 체크리스트 통과
|
||
- [ ] 콘텐츠 체크리스트 통과
|
||
- [ ] 상태 완결성(§4-1) — 입력 검증·되돌림·Esc 를 실제 조작으로 확인
|
||
- [ ] 해당하면 진실 완결성(§4-2) — 예시·AI·규제·생성 이미지의 오해 경로를 실제 상태로 확인
|
||
- [ ] 정적 CSS/JS의 stable URL을 바꿨다면 HTML 링크와 `@import` 의 버전을 함께 올렸고, 공개 CDN에서 실제 내려온 stylesheet URL과 새 토큰/규칙을 확인했다. HTML만 cache-bust하고 CSS가 이전 버전이면 배포 성공이 아니다
|
||
- [ ] 기능·접근성 자동 검사의 결과와 시각 평가(위계·브랜드·타입·구도·이미지·리듬)의 결과를 별도로 기록했다. 한쪽 PASS를 다른 쪽 PASS로 바꾸어 말하지 않았다
|
||
- [ ] 5장 여섯 질문과 `antipatterns.md` 검토를 프로젝트 계약·실제 렌더 근거로 기록했다
|
||
|
||
**하나라도 실패하면 출시가 아니라 4단계 복귀다.**
|
||
|
||
> 근거: research/references/04-ai-slop-signatures.md, research/motion/01-principles.md, research/three/04-performance.md (조사일 2026-08-20)
|