designpaca/packages/skill/references/layout.md
Yun Chan b92853bf2b
All checks were successful
ci / build (push) Successful in 23s
release / release (push) Successful in 36s
feat(skill): 색·모바일 내비를 인터뷰에 넣고 이미지 조달을 단계로 승격한다
실제로 한 페이지를 만들어 보고 드러난 것들이다.

0단계 인터뷰에 두 축을 더한다.

- 브랜드 색: 꽃집 작업에서 색을 묻지 않고 레퍼런스 실측 평균으로 정했다.
  결과는 좋았지만 브랜드 색이 있었다면 그걸 무시한 작업이 된다.
  "없다"는 답도 답이고, 그때는 피해야 할 색을 묻는다.
- 좁은 화면 내비: 항목 수는 0단계에 이미 정해져 있는데 구현에서 발견했다.
  2~4개는 쌓고, 5~6개는 가로 스크롤, 7개 이상만 여는 메뉴다.
  넷인데 햄버거를 쓰면 탭 한 번을 공짜로 뺏는 것이다.

4-0 이미지 조달 단계를 새로 만든다(references/images.md).

  자리를 만들기 전에 무엇을 실을지 정한다. codex 설치와 auth_mode 를 확인해
  생성 경로를 쓰고, 생성물이라는 사실을 design.md 에 남긴다.

  래퍼 실패 대응을 기록했다 — codex-cli 0.147.0 은 base64 를 돌려주지 않고
  ~/.codex/generated_images/<session>/exec-<id>.png 로 저장한다. 공식 래퍼는
  "image_gen 이 호출되지 않았다"며 실패하지만 파일은 멀쩡히 있다.
  실측에서 이 메시지를 보고 두 번 다시 만들었고 두 번 다 이미 있었다.

  싣기 전 최적화도 넣었다(실측 10.1MB → 603KB).

구현에서 넘어진 것 셋.

- images.md: <img width height> 를 적으면 그 height 가 계산된 높이가 되어
  aspect-ratio 가 조용히 무시된다. computed 는 "3 / 4" 로 멀쩡히 보이고
  실제 높이는 원본 1448px 이었다. height:auto 한 줄로 10.9 화면이 7 화면이 됐다.
- antipatterns.md: "컨트롤이 2줄로 접히나" 를 개별 높이로 재서 거짓 통과했다.
  링크는 한 줄짜리였고 줄바꿈된 것은 컨테이너였다(top 46/77).
  행 수는 높이가 아니라 top 값의 종류로 센다.
- typography.md: 세로쓰기에 가로쓰기 자간(0.14em)을 물리면 글자 사이 세로
  간격이 되어 낱글자가 흩어진다. 한글은 자소가 모여 한 글자라 특히 심하다.
- layout.md: 그리드 구조를 바꾸면 미디어쿼리도 같이 다시 써야 한다.
  넓은 화면은 멀쩡했고 390px 에서 헤드라인이 6줄이 됐다.
2026-08-21 04:13:03 +09:00

191 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# layout — 레이아웃과 타이포그래피
4-1 단계에서 읽는다. **이 단계가 끝나면 아무 이펙트 없이도 완성된 페이지**여야 한다. 그것이 이후 모든 폴백의 기반이다.
---
## 1. 그리드를 먼저 정한다
### 하나의 그리드에서 모든 것이 나온다
```css
.page {
display: grid;
grid-template-columns:
[full-start] minmax(var(--space-4), 1fr)
[wide-start] minmax(0, 12rem)
[main-start] minmax(0, var(--measure)) [main-end] /* 3단계에서 정한 값이다 */
minmax(0, 12rem) [wide-end]
minmax(var(--space-4), 1fr) [full-end];
}
.page > * { grid-column: main; }
.page > .wide { grid-column: wide; }
.page > .full { grid-column: full; }
```
**`main` 폭에 고정값을 쓰지 마라.** `--measure` 는 3단계에서 언어와 폰트에 맞춰 정한 값이다.
여기에 60rem 같은 숫자를 넣으면 본문이 measure 를 넘어가 이 문서의 통과 조건을 스스로 어긴다.
한글은 보통 라틴보다 좁다(35ch ≈ 561px vs 640px).
이 한 번의 정의로 **본문 폭 · 넓은 블록 · 전체 폭**이 전부 정렬된다. 섹션마다 `max-width``padding` 을 다시 쓰면 반드시 어긋난다.
### 비대칭을 두려워하지 마라
12열 중앙 정렬은 안전하고 잊힌다. 실제로 기억되는 레이아웃은 **의도적으로 한쪽으로 몰려 있다**. 다만 비대칭에도 규칙이 있어야 한다 — 아무 데나 놓는 것은 비대칭이 아니라 사고다.
- 텍스트 블록을 그리드의 2/3 지점에서 끊고 나머지를 비워두기
- 이미지를 화면 밖으로 흘려보내기(`full` 을 넘어 `margin-inline: calc(var(--space-4) * -1)`)
- 제목과 본문의 시작선을 일부러 어긋내기 — 단, **같은 어긋남을 페이지 전체에서 반복**할 때만
### 벤토 그리드 주의
벤토(크기가 다른 카드들의 격자)는 **더 이상 차별화가 아니라 새 기본값**이다. 효과는 있지만(스크롤 깊이 증가) 표준화가 끝나서 "고민 안 했음"의 신호로 읽힌다. 쓰려면 최소한 다음 중 하나는 해라:
- 카드 경계를 없애고 여백만으로 구획
- 그리드에서 한 칸을 의도적으로 비우기
- 카드 하나만 규칙을 깨고 밖으로 나가기
---
## 2. 시선 흐름
사람은 페이지를 읽지 않고 **훑는다.** 훑는 경로를 설계하는 것이 레이아웃의 본체다.
1. **첫 화면에서 세 가지만** — 무엇인지 / 왜 좋은지 / 다음 행동. 넷 이상이면 아무것도 안 읽힌다
2. **위계는 크기가 아니라 대비로 만든다** — 크기·굵기·색·여백 중 **둘 이상을 동시에** 바꿔야 위계가 보인다. 크기만 조금 키우는 것은 위계가 아니다
3. **시선을 한 번은 멈춰라** — 전부 같은 리듬으로 흐르면 아무것도 강조되지 않는다. 섹션 하나는 리듬을 깨야 한다
4. **스크롤은 보상이어야 한다** — 다음 화면에 무언가 새로운 것이 있어야 한다. 같은 카드 그리드가 세 번 반복되면 거기서 이탈한다
---
## 3. 타이포그래피
토큰은 3단계에서 정했다. 여기서는 **적용**이다.
폰트 자체의 로딩·기능·폴백은 `references/typography.md` 를 보라.
### 위계는 3단계면 충분하다
디스플레이 / 섹션 제목 / 본문. h4, h5, h6 까지 시각적으로 구분하려 들면 위계가 무너진다. 필요하면 **웨이트나 색**으로 구분해라, 새 크기를 만들지 말고.
### 본문이 주인공이다
헤드라인은 눈에 띄기 쉽다. **본문이 읽히는지**가 실력이다.
- 한 줄 길이(`--measure`)를 반드시 적용해라. 전체 폭 본문은 읽을 수 없다
- 문단 간격은 줄간격의 1.5배 이상. 들여쓰기와 문단 간격을 동시에 쓰지 마라
- 링크는 색만으로 구분하지 마라(밑줄 또는 다른 신호 병행)
### 한글이 들어가면
`references/antipatterns.md` 의 한글 조판 섹션을 읽어라. 요약:
- `word-break: keep-all` — 없으면 단어가 아무 데서나 잘린다
- line-height 1.6~1.8 (라틴보다 넉넉하게)
- 음수 자간 금지
- 한 줄 25~40자
- 라틴 폰트를 폴백 스택 **앞**에 둔다 (숫자·영문이 한글 폰트로 렌더되면 조악해진다)
- **한글 폰트를 지정하지 않는 것 자체가 완성도 미달 신호다**
---
## 4. 반응형
### 브레이크포인트가 아니라 콘텐츠에서 시작한다
```css
/* 나쁨: 기기 크기를 가정 */
@media (min-width: 768px) { }
/* 좋음: 콘텐츠가 깨지는 지점 */
.cards { grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); }
```
`auto-fit` + `minmax` 로 해결되는 것을 미디어쿼리로 만들지 마라. 미디어쿼리는 **레이아웃 구조 자체가 바뀔 때만** 쓴다.
### 모바일에서 먼저 확인해라
데스크톱에서 아름다운 것이 모바일에서 무너지는 것이 기본이고, 그 반대는 드물다. 특히:
- 큰 타이포는 모바일에서 반드시 줄여라 (`clamp` 의 최소값)
- 가로 스크롤이 생기는 요소를 찾아라 (`overflow-x: hidden` 으로 덮지 말고 원인을 고쳐라)
- 터치 타깃 44×44px 이상
- 호버로만 접근되는 기능을 만들지 마라
---
## 4-b. 모바일 내비 — 햄버거를 기본값으로 삼지 마라
내비 항목 수는 0단계에서 이미 정해져 있다(= 섹션 수). 구현하다 발견하면 늦다.
| 항목 수 | 처리 | 비용 |
|---|---|---|
| **2~4개** | 한 줄 유지. 자간을 줄이고 `space-between` 으로 편다 | 0 |
| **5~6개** | 가로 스크롤 줄, 또는 하단 고정 바 | 낮음 |
| **7개 이상** | 여는 메뉴 | `<details>` 로 JS 0바이트 |
**넷인데 햄버거를 쓰면 탭 한 번을 공짜로 뺏는 것이다.** 반대로 여섯을 한 줄에
욱여넣으면 접힌다 — 실측에서 링크가 두 줄(top 46/77)에 걸렸고, 워드마크까지 3줄이 됐다.
### 2~4개 — 쌓는 것이 접히는 것보다 낫다
워드마크와 내비를 한 줄에 두면 둘 다 접힌다. 좁은 화면에서는 **위아래로 쌓아라.**
```css
@media (max-width: 560px) {
.site-head { flex-direction: column; align-items: stretch; gap: var(--space-3); }
.nav { flex-wrap: nowrap; justify-content: space-between; letter-spacing: 0.04em; }
}
```
라벨 자간(`0.14em`)이 좁은 화면에서 폭을 크게 먹는다. **자간부터 줄여라**
폰트 크기를 줄이는 것보다 읽기에 덜 해롭다.
### 7개 이상 — `<details>` 면 JS 가 필요 없다
키보드 조작·`Esc`·포커스 이동이 브라우저 기본으로 온다.
직접 만든 토글은 그걸 전부 다시 구현해야 하고, 대개 빠뜨린다.
```html
<details class="nav-mobile">
<summary aria-label="메뉴"></summary>
<div class="nav-sheet"><a href="#a"></a></div>
</details>
```
```css
.nav-mobile > summary { list-style: none; cursor: pointer; }
.nav-mobile > summary::-webkit-details-marker { display: none; }
.nav-sheet { position: absolute; right: 0; }
```
**아이콘이 세 줄(≡)일 필요는 없다.** 에디토리얼이면 "메뉴" 라고 적는 편이 낫다 —
글자는 뜻이 분명하고, 세 줄은 학습된 관례일 뿐이다.
### 어느 쪽이든 검사는 같다
**항목의 `top` 값이 한 종류여야 한다.** 높이만 봐서는 못 잡는다(→ `antipatterns.md`).
```js
new Set([...document.querySelectorAll('.nav a')]
.map(e => Math.round(e.getBoundingClientRect().top))).size === 1
```
---
## 4-c. 구조를 바꾸면 미디어쿼리도 같이 다시 써라
실측 사고. 히어로를 12칸 그리드에서 "글 + 사진 컨테이너" 2단으로 바꾸면서
좁은 화면 규칙을 그대로 뒀다. `.hero-text``auto 1fr` 2칸인데
세로 라벨을 가로로 눕히자 **그 긴 문장이 auto 칸을 통째로 먹어** h1 칸이 짜부라졌고,
헤드라인이 390px 에서 6줄, 320px 에서 11줄이 됐다.
넓은 화면에서는 멀쩡했다. **구조 변경의 대가는 항상 좁은 화면에서 먼저 청구된다.**
> 규칙: 그리드 구조를 바꿨으면 **그 자리에서** 320·390·768 을 다시 재라.
> 나중에 하면 원인이 어느 변경이었는지 못 찾는다.
---
## 5. 이 단계의 통과 조건
- [ ] CSS/HTML만으로 페이지가 완성됐다. JS를 꺼도 읽힌다
- [ ] 모든 값이 3단계 토큰에서 나온다. 하드코딩된 px/색이 없다
- [ ] 첫 화면에 메시지가 셋 이하다
- [ ] 본문에 `--measure` 가 적용됐다
- [ ] 모바일 폭 **320px**(iPhone SE 세로)에서 가로 스크롤이 없다
- [ ] 키보드 Tab 만으로 모든 인터랙티브 요소에 도달한다. 포커스 링이 보인다
- [ ] 한글이 있다면 조판 규칙이 적용됐다
> 근거: research/references/02-methodology.md, 03-trends-2026.md, 04-ai-slop-signatures.md (조사일 2026-08-20)